Const/non-const pointer returning method

  • Follow


Hi,

  I am rather new to C++ and have run into a problem where I
haven't found an answer yet by searching (probably didn't find
the right search terms). I Have this simple program:

#include <iostream>

class A
{
  public:
    A( int i ) : m_ip( new int[ i ] ) { }
    int const * ip( ) const { std::cout << "const\n"; return m_ip; }
    int * ip( ) const { std::cerr << "non-const\n"; return m_ip; }

  private:
    int * m_ip;
};

int main( )
{
    A a( 10 );
    int const * ip = a.ip( );
    std::cout << ip[ 2 ] << '\n';
}

My exectation was that when calling ip() to get a const pointer
the compiler would be able to figure out I want it to use the
first ip() method that returns a const pointer. But it turns out
that always the second one is invoked. I'm not sure why and if
there's a way that I can make it pick the second one (short of
using different names for the methods)? I also noticed the same
effect when using const versus non-const references as return
values, also there the non-const returning function is called
eben when one asks for a const reference. Does all this only
work when overloading the [] operator?

                            Best regards, Jens
-- 
  \   Jens Thoms Toerring  ___      jt@toerring.de
   \__________________________      http://toerring.de
0
Reply jt68 (1134) 5/25/2010 6:03:05 PM

Jens Thoms Toerring wrote:

> Hi,
> 
>   I am rather new to C++ and have run into a problem where I
> haven't found an answer yet by searching (probably didn't find
> the right search terms). I Have this simple program:
> 
> #include <iostream>
> 
> class A
> {
>   public:
>     A( int i ) : m_ip( new int[ i ] ) { }
>     int const * ip( ) const { std::cout << "const\n"; return m_ip; }
>     int * ip( ) const { std::cerr << "non-const\n"; return m_ip; }
> 
>   private:
>     int * m_ip;
> };
> 
> int main( )
> {
>     A a( 10 );
>     int const * ip = a.ip( );
>     std::cout << ip[ 2 ] << '\n';
> }

Remark: as an illustration for the problem of which member function is 
called, the code is fine. Considered on its own, however, class A leaves 
room for improvement, e.g., with regard to memory management and 
encapsulation.

> My exectation was that when calling ip() to get a const pointer
> the compiler would be able to figure out I want it to use the
> first ip() method that returns a const pointer. But it turns out
> that always the second one is invoked.

You will have to adjust your expectations (if you have not already done so). 
The object a was not declared const. Hence any method call a.method() will 
always invoke the non-const version.

> I'm not sure why and if
> there's a way that I can make it pick the second one (short of
> using different names for the methods)?

Yes, you could do:

  A a ( 10 );
  A const & b ( a );    // be is a const alias for the object a.
  int const * ip = b.ip();

Alternatively, some trickery using casts would do.

BTW: why would you want the const method invoked?


> I also noticed the same
> effect when using const versus non-const references as return
> values, also there the non-const returning function is called
> eben when one asks for a const reference. Does all this only
> work when overloading the [] operator?

The operator[] is not different: the const version is called on const 
objects and the non-const version is called on non-const objects. So it is 
not clear, what you observed.


Best

Kai-Uwe Bux
0
Reply Kai 5/25/2010 6:37:07 PM


"Jens Thoms Toerring" <jt@toerring.de> wrote in message 
news:862hmpFgsqU1@mid.uni-berlin.de...
> Hi,
>
>  I am rather new to C++ and have run into a problem where I
> haven't found an answer yet by searching (probably didn't find
> the right search terms). I Have this simple program:
>
> #include <iostream>
>
> class A
> {
>  public:
>    A( int i ) : m_ip( new int[ i ] ) { }
>    int const * ip( ) const { std::cout << "const\n"; return m_ip; }
>    int * ip( ) const { std::cerr << "non-const\n"; return m_ip; }
>
>  private:
>    int * m_ip;
> };
>
> int main( )
> {
>    A a( 10 );
>    int const * ip = a.ip( );
>    std::cout << ip[ 2 ] << '\n';
> }
>
> My exectation was that when calling ip() to get a const pointer
> the compiler would be able to figure out I want it to use the
> first ip() method that returns a const pointer. But it turns out
> that always the second one is invoked. I'm not sure why and if
> there's a way that I can make it pick the second one (short of
> using different names for the methods)? I also noticed the same
> effect when using const versus non-const references as return
> values, also there the non-const returning function is called
> eben when one asks for a const reference. Does all this only
> work when overloading the [] operator?
>
>                            Best regards, Jens
> -- 
>  \   Jens Thoms Toerring  ___      jt@toerring.de
>   \__________________________      http://toerring.de

Either:

1) You are lying.

or

2) You are using a brain-dead compiler.

Why?  Because the code you posted is ill-formed so shouldn't compile.  You 
cannot overload a function which differs only by return type.

/Leigh 

0
Reply Leigh 5/25/2010 6:40:59 PM

On May 25, 2:03=A0pm, j...@toerring.de (Jens Thoms Toerring) wrote:
> Hi,
>
> =A0 I am rather new to C++ and have run into a problem where I
> haven't found an answer yet by searching (probably didn't find
> the right search terms). I Have this simple program:
>
> #include <iostream>
>
> class A
> {
> =A0 public:
> =A0 =A0 A( int i ) : m_ip( new int[ i ] ) { }
> =A0 =A0 int const * ip( ) const { std::cout << "const\n"; return m_ip; }
> =A0 =A0 int * ip( ) const { std::cerr << "non-const\n"; return m_ip; }
>
> =A0 private:
> =A0 =A0 int * m_ip;
>
> };
>
> int main( )
> {
> =A0 =A0 A a( 10 );
> =A0 =A0 int const * ip =3D a.ip( );
> =A0 =A0 std::cout << ip[ 2 ] << '\n';
>
> }
>
> My exectation was that when calling ip() to get a const pointer
> the compiler would be able to figure out I want it to use the
> first ip() method that returns a const pointer. But it turns out
> that always the second one is invoked. I'm not sure why and if
> there's a way that I can make it pick the second one (short of
> using different names for the methods)? I also noticed the same
> effect when using const versus non-const references as return
> values, also there the non-const returning function is called
> eben when one asks for a const reference. Does all this only
> work when overloading the [] operator?
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Best regards, Jen=
s
> --
> =A0 \ =A0 Jens Thoms Toerring =A0___ =A0 =A0 =A0j...@toerring.de
> =A0 =A0\__________________________ =A0 =A0 =A0http://toerring.de

first off, the following is not a const ptr:
int const * p; // mutable pointer to a constant
but this is a const ptr to a mutable integer:
int * const p

in C++, one would instead use a std::vector with [] or at(), in the
case you really do prefer a primitive array, use a template.

template< typename T, std::size_t SIZE >
class A
{=A8
  T m_t[ SIZE ];
public:
  A() { } // def ctor required for type T
  T& operator[](const std::size_t i) { return m_t[i]; }
};

Automatic allocation is safer, easier and preferred. Only new when you
absolutely must.

0
Reply Salt_Peter 5/25/2010 6:43:16 PM

* Jens Thoms Toerring, on 25.05.2010 20:03:
>
>    I am rather new to C++ and have run into a problem where I
> haven't found an answer yet by searching (probably didn't find
> the right search terms). I Have this simple program:
>
> #include<iostream>
>
> class A
> {
>    public:
>      A( int i ) : m_ip( new int[ i ] ) { }
>      int const * ip( ) const { std::cout<<  "const\n"; return m_ip; }
>      int * ip( ) const { std::cerr<<  "non-const\n"; return m_ip; }
>
>    private:
>      int * m_ip;
> };
>
> int main( )
> {
>      A a( 10 );
>      int const * ip = a.ip( );
>      std::cout<<  ip[ 2 ]<<  '\n';
> }

Do you?


<example>
C:\test> gnuc x.cpp
x.cpp:8: error: 'int* A::ip() const' cannot be overloaded
x.cpp:7: error: with 'const int* A::ip() const'

C:\test> msvc x.cpp
x.cpp
x.cpp(8) : error C2556: 'int *A::ip(void) const' : overloaded function differs 
only by return type from 'const int *A::i
p(void) const'
         x.cpp(7) : see declaration of 'A::ip'
x.cpp(8) : error C2373: 'A::ip' : redefinition; different type modifiers
         x.cpp(7) : see declaration of 'A::ip'
x.cpp(8) : error C2143: syntax error : missing ';' before '<<'
x.cpp(8) : warning C4517: access-declarations are deprecated; member 
using-declarations provide a better alternative
x.cpp(8) : error C2886: 'std::cerr' : symbol cannot be used in a member 
using-declaration
         C:\Program Files\Microsoft Visual Studio .NET 
2003\Vc7\include\iostream(14) : see declaration of 'std::cerr'
x.cpp(8) : error C2238: unexpected token(s) preceding ';'
x.cpp(8) : error C2059: syntax error : 'return'
x.cpp(8) : error C2238: unexpected token(s) preceding ';'
x.cpp(10) : error C2143: syntax error : missing ';' before ':'
x.cpp(10) : error C2059: syntax error : ':'
x.cpp(12) : error C2059: syntax error : '}'
x.cpp(12) : error C2143: syntax error : missing ';' before '}'
x.cpp(12) : error C2059: syntax error : '}'
x.cpp(17) : error C2264: 'A::ip' : error in function definition or declaration; 
function not called

C:\test> _
</example>



> My exectation was that when calling ip() to get a const pointer
> the compiler would be able to figure out I want it to use the
> first ip() method that returns a const pointer. But it turns out
> that always the second one is invoked.

I rather doubt it.

First your program needs to compile.


> I'm not sure why and if
> there's a way that I can make it pick the second one (short of
> using different names for the methods)? I also noticed the same
> effect when using const versus non-const references as return
> values, also there the non-const returning function is called
> eben when one asks for a const reference. Does all this only
> work when overloading the [] operator?

As a first step, get your program to compile.

You can safely disregard the earlier comments in this thread until your code 
compiles.

And then it may turn out that the code that compiles is not what those comments 
are about.


Cheers & hth.,

- Alf

-- 
blog at <url: http://alfps.wordpress.com>
0
Reply Alf 5/25/2010 7:13:51 PM

On May 25, 10:03=A0pm, j...@toerring.de (Jens Thoms Toerring) wrote:
> Hi,
>
> =A0 I am rather new to C++ and have run into a problem where I
> haven't found an answer yet by searching (probably didn't find
> the right search terms). I Have this simple program:
>
> #include <iostream>
>
> class A
> {
> =A0 public:
> =A0 =A0 A( int i ) : m_ip( new int[ i ] ) { }
> =A0 =A0 int const * ip( ) const { std::cout << "const\n"; return m_ip; }
> =A0 =A0 int * ip( ) const { std::cerr << "non-const\n"; return m_ip; }
>
> =A0 private:
> =A0 =A0 int * m_ip;
>
> };
>
> int main( )
> {
> =A0 =A0 A a( 10 );
> =A0 =A0 int const * ip =3D a.ip( );
> =A0 =A0 std::cout << ip[ 2 ] << '\n';
>
> }
>
> My exectation was that when calling ip() to get a const pointer
> the compiler would be able to figure out I want it to use the
> first ip() method that returns a const pointer. But it turns out
> that always the second one is invoked. I'm not sure why and if
> there's a way that I can make it pick the second one (short of
> using different names for the methods)? I also noticed the same
> effect when using const versus non-const references as return
> values, also there the non-const returning function is called
> eben when one asks for a const reference. Does all this only
> work when overloading the [] operator?
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Best regards, Jen=
s
> --
> =A0 \ =A0 Jens Thoms Toerring =A0___ =A0 =A0 =A0j...@toerring.de
> =A0 =A0\__________________________ =A0 =A0 =A0http://toerring.de

Hi Jens

At first your code doesn't work. You can't overload
a function just base on different return type.
I guess your ip member functions should be like this:
    int const * ip( ) const { std::cout << "const\n"; return m_ip; }
    int * ip( ) { std::cerr << "non-const\n"; return m_ip; }
Second, if you allocate memory in construtor,
you must free it in destructor:
    A( int i ) : m_ip( new int[i]) { } // new an array
    ~A() { delete [] ip; } // delete the array
Third, You didn't initialize your array. Constructor
is the best way for initialization. For example:
  A( int i ) : m_ip( new int[ i ] )
      {
        std::fill(m_ip, m_ip + i, 0);
      }
about your question:
the const member function means
  1. You don't want to change the state of object via it
  2. For const object, just const member function should be called.
  It is the obvious result of #1

See the following code:
    A a( 10 );
    int const * ip =3D a.ip();
    ip[0]++;  // error *ip is const;
    int* ip2 =3D a.ip();
    ip2[1]++;  // OK: *ip2 is not const
    const A a2(20);
    a2.ip(); // calling const ip

Regards,
  -- Saeed Amrollahi
0
Reply Saeed 5/25/2010 7:14:27 PM

Kai-Uwe Bux <jkherciueh@gmx.net> wrote:
> Jens Thoms Toerring wrote:
> >   I am rather new to C++ and have run into a problem where I
> > haven't found an answer yet by searching (probably didn't find
> > the right search terms). I Have this simple program:
> > 
> > #include <iostream>
> > 
> > class A
> > {
> >   public:
> >     A( int i ) : m_ip( new int[ i ] ) { }
> >     int const * ip( ) const { std::cout << "const\n"; return m_ip; }
                          ^^^^^
Sorry, that was a mistake just before copy-and-paste...

> >     int * ip( ) const { std::cerr << "non-const\n"; return m_ip; }
> > 
> >   private:
> >     int * m_ip;
> > };
> > 
> > int main( )
> > {
> >     A a( 10 );
> >     int const * ip = a.ip( );
> >     std::cout << ip[ 2 ] << '\n';
> > }

> Remark: as an illustration for the problem of which member function is 
> called, the code is fine. Considered on its own, however, class A leaves 
> room for improvement, e.g., with regard to memory management and 
> encapsulation.

Yes, of course, this wasn't meant to be production quality code
but just a bare-bones example, so it leaks memory etc.

> > My exectation was that when calling ip() to get a const pointer
> > the compiler would be able to figure out I want it to use the
> > first ip() method that returns a const pointer. But it turns out
> > that always the second one is invoked.

> You will have to adjust your expectations (if you have not already done so). 
> The object a was not declared const. Hence any method call a.method() will 
> always invoke the non-const version.

Well, I am in the process of adjusting my expectations all the
time;-) That's part of the fun of learning a new language...

> > I'm not sure why and if
> > there's a way that I can make it pick the second one (short of
> > using different names for the methods)?

> Yes, you could do:

>   A a ( 10 );
>   A const & b ( a );    // be is a const alias for the object a.
>   int const * ip = b.ip();

> Alternatively, some trickery using casts would do.

> BTW: why would you want the const method invoked?

That's a bit longer story: The array in the class will be an
array of pointers to rather large amounts of data. And I will
need lots of copies of that class. In the copies typically
only small subsets of the data will have to be changed. Thus,
to keep the total amount of memory used down, my idea was to
have boost::shared_ptr's in the array (thus having a refe-
rence count and automatic deallocation) and to make a "real"
copy of an element only when it is needed, i.e. when a non-
const instance of the element is requested and the reference
count isn't 1. For that I had hoped for the function for re-
turning a const reference/pointer to be invoked when a const
reference/pointer is requested and the non-const returning
version otherwise (in which then a copy is made when neces-
sary). And then, of course, I hoped to make all that com-
pletely transparent to the user of the class, so they don't
have to think too much about what they're doing...

> > I also noticed the same
> > effect when using const versus non-const references as return
> > values, also there the non-const returning function is called
> > eben when one asks for a const reference. Does all this only
> > work when overloading the [] operator?

> The operator[] is not different: the const version is called on const 
> objects and the non-const version is called on non-const objects. So it is 
> not clear, what you observed.

Probably my observations weren't very good. to be honest at
the moment I'm still a bit overloaded with understanding
what is happening when;-) But your explanation has hopefully
cleared up a few misconceptions.

                              Best regards, Jens
-- 
  \   Jens Thoms Toerring  ___      jt@toerring.de
   \__________________________      http://toerring.de
0
Reply jt 5/25/2010 7:47:08 PM

Saeed Amrollahi <amrollahi.saeed@gmail.com> wrote:
> On May 25, 10:03 pm, j...@toerring.de (Jens Thoms Toerring) wrote:
> > Hi,
> >
> >   I am rather new to C++ and have run into a problem where I
> > haven't found an answer yet by searching (probably didn't find
> > the right search terms). I Have this simple program:
> >
> > #include <iostream>
> >
> > class A
> > {
> >   public:
> >     A( int i ) : m_ip( new int[ i ] ) { }
> >     int const * ip( ) const { std::cout << "const\n"; return m_ip; }
> >     int * ip( ) const { std::cerr << "non-const\n"; return m_ip; }
> >
> >   private:
> >     int * m_ip;
> >
> > };
> >
> > int main( )
> > {
> >     A a( 10 );
> >     int const * ip = a.ip( );
> >     std::cout << ip[ 2 ] << '\n';
> >
> > }
> >
> > My exectation was that when calling ip() to get a const pointer
> > the compiler would be able to figure out I want it to use the
> > first ip() method that returns a const pointer. But it turns out
> > that always the second one is invoked. I'm not sure why and if
> > there's a way that I can make it pick the second one (short of
> > using different names for the methods)? I also noticed the same
> > effect when using const versus non-const references as return
> > values, also there the non-const returning function is called
> > eben when one asks for a const reference. Does all this only
> > work when overloading the [] operator?
> >
> >                             Best regards, Jens
> > --
> >   \   Jens Thoms Toerring  ___      j...@toerring.de
> >    \__________________________      http://toerring.de

> Hi Jens

> At first your code doesn't work. You can't overload
> a function just base on different return type.
> I guess your ip member functions should be like this:
>     int const * ip( ) const { std::cout << "const\n"; return m_ip; }
>     int * ip( ) { std::cerr << "non-const\n"; return m_ip; }

Yes, exactly - obviously a gone-wrong last minute change
before pasting it into my post. Won't happen again if I
can avoid it.

> Second, if you allocate memory in construtor,
> you must free it in destructor:
>     A( int i ) : m_ip( new int[i]) { } // new an array
>     ~A() { delete [] ip; } // delete the array
> Third, You didn't initialize your array. Constructor
> is the best way for initialization. For example:
>   A( int i ) : m_ip( new int[ i ] )
>       {
>         std::fill(m_ip, m_ip + i, 0);
>       }

Yes, had snipped all that parts since I wanted to example
as short as possible.

> about your question:
> the const member function means
>   1. You don't want to change the state of object via it
>   2. For const object, just const member function should be called.
>   It is the obvious result of #1

I hadn't been aware that the const-returning function would
only be invoked for a const object but laboured under the
wrong impression that what I assign it to would make a dif-
ference. I hope I will keep that in mind in the future;-)

> See the following code:
>     A a( 10 );
>     int const * ip = a.ip();
>     ip[0]++;  // error *ip is const;
>     int* ip2 = a.ip();
>     ip2[1]++;  // OK: *ip2 is not const
>     const A a2(20);
>     a2.ip(); // calling const ip

Yes, I see.
                  Thanks and best regards, Jens

-- 
  \   Jens Thoms Toerring  ___      jt@toerring.de
   \__________________________      http://toerring.de
0
Reply jt 5/25/2010 7:59:19 PM

Jens Thoms Toerring wrote:

> Kai-Uwe Bux <jkherciueh@gmx.net> wrote:
>> Jens Thoms Toerring wrote:
>> >   I am rather new to C++ and have run into a problem where I
>> > haven't found an answer yet by searching (probably didn't find
>> > the right search terms). I Have this simple program:
>> > 
>> > #include <iostream>
>> > 
>> > class A
>> > {
>> >   public:
>> >     A( int i ) : m_ip( new int[ i ] ) { }
>> >     int const * ip( ) const { std::cout << "const\n"; return m_ip; }
>                           ^^^^^
> Sorry, that was a mistake just before copy-and-paste...
> 
>> >     int * ip( ) const { std::cerr << "non-const\n"; return m_ip; }
>> > 
>> >   private:
>> >     int * m_ip;
>> > };
>> > 
>> > int main( )
>> > {
>> >     A a( 10 );
>> >     int const * ip = a.ip( );
>> >     std::cout << ip[ 2 ] << '\n';
>> > }

[...]
>> > I'm not sure why and if
>> > there's a way that I can make it pick the second one (short of
>> > using different names for the methods)?
> 
>> Yes, you could do:
> 
>>   A a ( 10 );
>>   A const & b ( a );    // be is a const alias for the object a.
>>   int const * ip = b.ip();
> 
>> Alternatively, some trickery using casts would do.
> 
>> BTW: why would you want the const method invoked?
> 
> That's a bit longer story: The array in the class will be an
> array of pointers to rather large amounts of data. And I will
> need lots of copies of that class. In the copies typically
> only small subsets of the data will have to be changed. Thus,
> to keep the total amount of memory used down, my idea was to
> have boost::shared_ptr's in the array (thus having a refe-
> rence count and automatic deallocation) and to make a "real"
> copy of an element only when it is needed, i.e. when a non-
> const instance of the element is requested and the reference
> count isn't 1. For that I had hoped for the function for re-
> turning a const reference/pointer to be invoked when a const
> reference/pointer is requested and the non-const returning
> version otherwise (in which then a copy is made when neces-
> sary). And then, of course, I hoped to make all that com-
> pletely transparent to the user of the class, so they don't
> have to think too much about what they're doing...

I see: you want copy-on-write. The problem is _where_ and _how_ the copy-on-
write should be handled. It is somewhat tricky to use COW with classes that 
have not been designed with that in mind. Your options include:

a) If you control the classes that your container should contain, then have 
them handle the COW transparently and just use std::vector (or some other 
container type from STL) as the container. The copy will be made 
transparently when a non-const member function on the retreived object is 
invoked.

b) Change the interface of the container so that you don't rely on 
"overloading via return type". E.g.: have different names for functions 
returning const references or do something like:

  void get_ptr ( T const * & p_ref, size_type index );
  void get_ptr ( T * & p_ref, size_type index );


Best

Kai-Uwe Bux

0
Reply Kai 5/25/2010 8:10:46 PM

On May 25, 9:10 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> Jens Thoms Toerring wrote:
> > Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> >> Jens Thoms Toerring wrote:
> >> >   I am rather new to C++ and have run into a problem where I
> >> > haven't found an answer yet by searching (probably didn't find
> >> > the right search terms). I Have this simple program:

> >> > #include <iostream>

> >> > class A
> >> > {
> >> >   public:
> >> >     A( int i ) : m_ip( new int[ i ] ) { }
> >> >     int const * ip( ) const { std::cout << "const\n"; return m_ip; }
> >                           ^^^^^
> > Sorry, that was a mistake just before copy-and-paste...

> >> >     int * ip( ) const { std::cerr << "non-const\n"; return m_ip; }

> >> >   private:
> >> >     int * m_ip;
> >> > };

> >> > int main( )
> >> > {
> >> >     A a( 10 );
> >> >     int const * ip = a.ip( );
> >> >     std::cout << ip[ 2 ] << '\n';
> >> > }

> [...]

> >> > I'm not sure why and if there's a way that I can make it
> >> > pick the second one (short of using different names for
> >> > the methods)?

> >> Yes, you could do:

> >>   A a ( 10 );
> >>   A const & b ( a );    // be is a const alias for the object a.
> >>   int const * ip = b.ip();

That's awkward.  And if the goal is to have different behavior
depending on what the client code does with the results, it's
very error prone, even supposing you control all of the client
code.

> >> Alternatively, some trickery using casts would do.

> >> BTW: why would you want the const method invoked?

> > That's a bit longer story: The array in the class will be an
> > array of pointers to rather large amounts of data. And I
> > will need lots of copies of that class. In the copies
> > typically only small subsets of the data will have to be
> > changed. Thus, to keep the total amount of memory used down,
> > my idea was to have boost::shared_ptr's in the array (thus
> > having a refe- rence count and automatic deallocation) and
> > to make a "real" copy of an element only when it is needed,
> > i.e. when a non- const instance of the element is requested
> > and the reference count isn't 1. For that I had hoped for
> > the function for re- turning a const reference/pointer to be
> > invoked when a const reference/pointer is requested and the
> > non-const returning version otherwise (in which then a copy
> > is made when neces- sary). And then, of course, I hoped to
> > make all that com- pletely transparent to the user of the
> > class, so they don't have to think too much about what
> > they're doing...

> I see: you want copy-on-write. The problem is _where_ and
> _how_ the copy-on- write should be handled. It is somewhat
> tricky to use COW with classes that have not been designed
> with that in mind. Your options include:

> a) If you control the classes that your container should
> contain, then have them handle the COW transparently and just
> use std::vector (or some other container type from STL) as the
> container. The copy will be made transparently when a
> non-const member function on the retreived object is invoked.

> b) Change the interface of the container so that you don't
> rely on "overloading via return type". E.g.: have different
> names for functions returning const references or do something
> like:

>   void get_ptr ( T const * & p_ref, size_type index );
>   void get_ptr ( T * & p_ref, size_type index );

The usual solution in such cases is to return a proxy class, so
that you can effectively overload on what the client code does
with the object.

--
James Kanze
0
Reply James 5/25/2010 8:47:11 PM

James Kanze wrote:

> On May 25, 9:10 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>> Jens Thoms Toerring wrote:
>> > Kai-Uwe Bux <jkherci...@gmx.net> wrote:
>> >> Jens Thoms Toerring wrote:
[...]
>> > That's a bit longer story: The array in the class will be an
>> > array of pointers to rather large amounts of data. And I
>> > will need lots of copies of that class. In the copies
>> > typically only small subsets of the data will have to be
>> > changed. Thus, to keep the total amount of memory used down,
>> > my idea was to have boost::shared_ptr's in the array (thus
>> > having a refe- rence count and automatic deallocation) and
>> > to make a "real" copy of an element only when it is needed,
>> > i.e. when a non- const instance of the element is requested
>> > and the reference count isn't 1. For that I had hoped for
>> > the function for re- turning a const reference/pointer to be
>> > invoked when a const reference/pointer is requested and the
>> > non-const returning version otherwise (in which then a copy
>> > is made when neces- sary). And then, of course, I hoped to
>> > make all that com- pletely transparent to the user of the
>> > class, so they don't have to think too much about what
>> > they're doing...
> 
>> I see: you want copy-on-write. The problem is _where_ and
>> _how_ the copy-on- write should be handled. It is somewhat
>> tricky to use COW with classes that have not been designed
>> with that in mind. Your options include:
> 
>> a) If you control the classes that your container should
>> contain, then have them handle the COW transparently and just
>> use std::vector (or some other container type from STL) as the
>> container. The copy will be made transparently when a
>> non-const member function on the retreived object is invoked.
> 
>> b) Change the interface of the container so that you don't
>> rely on "overloading via return type". E.g.: have different
>> names for functions returning const references or do something
>> like:
> 
>>   void get_ptr ( T const * & p_ref, size_type index );
>>   void get_ptr ( T * & p_ref, size_type index );
> 
> The usual solution in such cases is to return a proxy class, so
> that you can effectively overload on what the client code does
> with the object.

In my experience, that proxy class tends to grow over time and in the end it 
forwards all member functions of the underlying class to make informed and 
well-suited decisions on whether to copy or not. Effectively, one writes a 
wrapper that essentially reproduces option (a).

Of course, if we could overload the dot-operator ... <g>


However, you are correct: I missed that option, which I should have 
mentioned.


Best

Kai-Uwe Bux
0
Reply Kai 5/25/2010 9:01:20 PM

Kai-Uwe Bux <jkherciueh@gmx.net> wrote:
> James Kanze wrote:
> > On May 25, 9:10 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> >> Jens Thoms Toerring wrote:
> >> > Kai-Uwe Bux <jkherci...@gmx.net> wrote:
 
> >> I see: you want copy-on-write.

Yes.

> The problem is _where_ and
> >> _how_ the copy-on- write should be handled.

Yes, exactly;-)

> It is somewhat
> >> tricky to use COW with classes that have not been designed
> >> with that in mind. Your options include:
> > 
> >> a) If you control the classes that your container should
> >> contain, then have them handle the COW transparently and just
> >> use std::vector (or some other container type from STL) as the
> >> container. The copy will be made transparently when a
> >> non-const member function on the retreived object is invoked.
> > 
> >> b) Change the interface of the container so that you don't
> >> rely on "overloading via return type". E.g.: have different
> >> names for functions returning const references or do something
> >> like:
> > 
> >>   void get_ptr ( T const * & p_ref, size_type index );
> >>   void get_ptr ( T * & p_ref, size_type index );
> > 
> > The usual solution in such cases is to return a proxy class, so
> > that you can effectively overload on what the client code does
> > with the object.

> In my experience, that proxy class tends to grow over time and in the end it 
> forwards all member functions of the underlying class to make informed and 
> well-suited decisions on whether to copy or not. Effectively, one writes a 
> wrapper that essentially reproduces option (a).

> Of course, if we could overload the dot-operator ... <g>

Thanks, you gave me quite a number of new ideas I have to read
up upon and think about...
                              Best regards, Jens
-- 
  \   Jens Thoms Toerring  ___      jt@toerring.de
   \__________________________      http://toerring.de
0
Reply jt 5/25/2010 9:09:06 PM

Jens Thoms Toerring wrote:
> I hadn't been aware that the const-returning function would
> only be invoked for a const object but laboured under the
> wrong impression that what I assign it to would make a dif-
> ference. I hope I will keep that in mind in the future;-)

Just to summarize:
-  Non-const objects can call their non-const or const functions.  If
the function being called is overloaded with both a const and a non-
const version, then non-const objects will call their non-const
version.
-  const objects can call their const functions.
0
Reply John 5/26/2010 4:51:59 PM

12 Replies
118 Views

(page loaded in 0.139 seconds)

Similiar Articles:


















7/23/2012 6:06:18 PM


Reply: