Const/non-const pointer returning method

  • Thread starter Jens Thoms Toerring
  • Start date
J

Jens Thoms Toerring

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
 
K

Kai-Uwe Bux

Jens said:
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
 
S

Salt_Peter

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

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

T m_t[ SIZE ];
public:
A() { } // def ctor required for type T
T& operator[](const std::size_t i) { return m_t; }
};

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

Alf P. Steinbach

* 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
 
S

Saeed Amrollahi

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

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) { } // 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 = 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

Regards,
-- Saeed Amrollahi
 
J

Jens Thoms Toerring

Kai-Uwe Bux said:
Jens said:
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.
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...
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
 
J

Jens Thoms Toerring

Saeed Amrollahi said:
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
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) { } // 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
 
K

Kai-Uwe Bux

Jens said:
Kai-Uwe Bux said:
Jens said:
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';
}
[...]
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
 
J

James Kanze

Jens said:
Kai-Uwe Bux said:
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.
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.
 
K

Kai-Uwe Bux

James said:
Jens said:
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
 
J

Jens Thoms Toerring

Kai-Uwe Bux said:
Yes.

The problem is _where_ and

Yes, exactly;-)
It is somewhat
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
 
J

John H.

Jens said:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top