473,503 Members | 3,739 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Const correctness for pointer data members

Hi all,

I have been deling with this kind of code:

class Foo
{
public:
void NonConstMethod()
{}
};

class Bar
{
public:
// [...] (Class simplified)

void NonLogicallyConstMethod() const
{
m_pBar->NonConstMethod();
}
private:
Foo* const m_pBar;

};

Although this is accepted by the compiler, and therefore const-correct,
I often find myself puzzled as to whether this is actually and
logically const-correct.
It just happens that NonLogicallyConstMethod() can invoke a const
method because of the way Bar is associated to Foo i.e. If I used a
class member variable this would not be allowed. The fact that the
pointer itself is const looks like a workaround (not unlike using
<mutable>).

What am I missing?
Thanks,
Quantdev2004

Oct 4 '05 #1
10 2266
On 4 Oct 2005 07:13:50 -0700, qu**********@yahoo.co.uk wrote:
Hi all,

I have been deling with this kind of code:

class Foo
{
public:
void NonConstMethod()
{}
};

class Bar
{
public:
// [...] (Class simplified)

void NonLogicallyConstMethod() const
{
m_pBar->NonConstMethod();
}
private:
Foo* const m_pBar;

};

Although this is accepted by the compiler, and therefore const-correct,
I often find myself puzzled as to whether this is actually and
logically const-correct.
It just happens that NonLogicallyConstMethod() can invoke a const
method because of the way Bar is associated to Foo i.e. If I used a
class member variable this would not be allowed. The fact that the
pointer itself is const looks like a workaround (not unlike using
<mutable>).

What am I missing?
Thanks,
Quantdev2004


What you are missing is that the const-ness (or in C++ standard-speak,
the "cv-qualification") of the pointer has absolutely nothing to do
with the const-ness (or "cv-qualification") of the thing(s) it points
to. These are two totally and fundamentally different things.

--
Bob Hairgrove
No**********@Home.com
Oct 4 '05 #2
qu**********@yahoo.co.uk wrote:
I have been deling with this kind of code:

class Foo
{
public:
void NonConstMethod()
{}
};

class Bar
{
public:
// [...] (Class simplified)

void NonLogicallyConstMethod() const
{
m_pBar->NonConstMethod();
}
private:
Foo* const m_pBar;
It's a constant pointer to a mutable (non-constant) Foo.

};

Although this is accepted by the compiler, and therefore const-correct,
I often find myself puzzled as to whether this is actually and
logically const-correct.
Unknown. Does 'Bar' *own* his copy of 'Foo', to which 'm_pBar' (BTW, do
you think that the name could be a bit corrected, like 'm_pFoo'?) is
pointing? If it does own it, then you're probably right, the logic is
a bit screwed up. If it does not own it, it probably does not matter.
It just happens that NonLogicallyConstMethod() can invoke a const
method
Isn't it actually vice versa: it can invoke a NON-const method?
because of the way Bar is associated to Foo i.e. If I used a
class member variable this would not be allowed.
In that case the 'Foo' *object* itself would be const.
The fact that the
pointer itself is const looks like a workaround (not unlike using
<mutable>).

What am I missing?


A good book, maybe? And thinking about what to allow and what not to
allow in your own classes...

V
Oct 4 '05 #3
quantdev2...@yahoo.co.uk wrote:
Hi all,

I have been deling with this kind of code:

class Foo
{
public:
void NonConstMethod()
{}
};

class Bar
{
public:
// [...] (Class simplified)

void NonLogicallyConstMethod() const
{
m_pBar->NonConstMethod();
}
private:
Foo* const m_pBar;

};

Although this is accepted by the compiler, and therefore const-correct,
I often find myself puzzled as to whether this is actually and
logically const-correct.
It just happens that NonLogicallyConstMethod() can invoke a const
method because of the way Bar is associated to Foo i.e. If I used a
class member variable this would not be allowed. The fact that the
pointer itself is const looks like a workaround (not unlike using
<mutable>).

What am I missing?
Thanks,
Quantdev2004


You're not missing anything. Constness is shallow. That is, C++ does
not transfer constness from the pointer to the pointee. (In your case,
m_pBar is always const, but if you removed that const, it would become
const in const methods, though the pointee would not).

There have been many discussions on this NG and others about why this
is or is not a violation of const-correctness. I find the behavior
non-intuitive and think constness should be transferred to the pointee
in these cases and overridden when necessary with mutable-like
declaration, but changing the language would break a good deal of
existing code.

To get the behavior you want, you can do something like this:

template <class T>
class DeepPtr
{
public:
DeepPtr( T *const ptr ) : m_ptr( ptr ) { assert(m_ptr); }
DeepPtr( DeepPtr<T>& ptr ) : m_ptr( ptr.m_ptr ) {}

// Standard access
T* operator->() { return m_ptr; }
T& operator*() { return *m_ptr; }
T& operator[]( ui32 n ) { return m_ptr[ n ]; }

// Make pointee const if pointer is const
T const* operator->() const { return m_ptr; }
T const& operator*() const { return *m_ptr; }
T const& operator[]( ui32 n ) const { return m_ptr[ n ]; }

private:
T * const m_ptr;

// Disabled methods
DeepPtr( const DeepPtr& );
DeepPtr& operator=( const DeepPtr& );
};

struct Foo
{
void NonConst() {};
};

struct Bar
{
Bar( Foo* pFoo ) : m_pFoo( pFoo ) {}
void Const() const { m_pFoo->NonConst(); } // Error!
private:
DeepPtr<Foo> m_pFoo;
};

Unfortunately, the disabled copy constructor and assignment operator
mean that such a pointer cannot be used in a standard container.

Cheers! --M

Oct 4 '05 #4
qu**********@yahoo.co.uk wrote:


Although this is accepted by the compiler, and therefore const-correct,
I often find myself puzzled as to whether this is actually and
logically const-correct.
It just happens that NonLogicallyConstMethod() can invoke a const
method because of the way Bar is associated to Foo i.e. If I used a
class member variable this would not be allowed. The fact that the
pointer itself is const looks like a workaround (not unlike using
<mutable>).

What am I missing?


foo* bar; A pointer. Neither the pointer not what it points to is const
foo* const bar; A pointer. The pointer itself is const. But not the object
the pointer points to. In other words: While it is illegal to
make the pointer point to another object, you can change the object
as often as you want

foo const * bar; A pointer. The pointer is not const, but the object the pointer points
to is. This means, the pointer can be reseated to point to different objects
but it is illegal to attempt to change the objects themselfs.

foo const * const bar; Another pointer. This time the pointer and what it points to is const.
Neither can the pointer be reseated to a different object, nor can the object
itself be changed through this pointer

const foo * const bar; identical to foo const * const bar;
const applies to the thing on its left, with the only exception if const is the leftmost specifier.
Then it applies to the thing on its right.

As for your class. Only the things in your class are 'protected' in a const member function. The
pointer
is a part of your class, but not the object the pointer points to.

--
Karl Heinz Buchegger
kb******@gascad.at
Oct 4 '05 #5
mlimber wrote:
[snip]

template <class T>
class DeepPtr
{
public:
DeepPtr( T *const ptr ) : m_ptr( ptr ) { assert(m_ptr); }
DeepPtr( DeepPtr<T>& ptr ) : m_ptr( ptr.m_ptr ) {}

// Standard access
T* operator->() { return m_ptr; }
T& operator*() { return *m_ptr; }
T& operator[]( ui32 n ) { return m_ptr[ n ]; }

// Make pointee const if pointer is const
T const* operator->() const { return m_ptr; }
T const& operator*() const { return *m_ptr; }
T const& operator[]( ui32 n ) const { return m_ptr[ n ]; }

private:
T * const m_ptr;

// Disabled methods
DeepPtr( const DeepPtr& );
DeepPtr& operator=( const DeepPtr& );
};

[snip]

BTW, I should have included <cassert> and ui32 should be translated to
size_t or unsigned int or whatever.

Cheers! --M

Oct 4 '05 #6
> Unknown. Does 'Bar' *own* his copy of 'Foo', to which 'm_pBar' (BTW, do
you think that the name could be a bit corrected, like 'm_pFoo'?)
yes, it's m_pFoo;
is
pointing? If it does own it, then you're probably right, the logic is
a bit screwed up. If it does not own it, it probably does not matter.
Ownership it's a good discriminant, I didn't think about it!
It just happens that NonLogicallyConstMethod() can invoke a const
method


Isn't it actually vice versa: it can invoke a NON-const method?


you're right again, sorry about the typos!
> because of the way Bar is associated to Foo i.e. If I used a
class member variable this would not be allowed.


In that case the 'Foo' *object* itself would be const.


that's what I find strange the fact that a syntactic detail (having the
object on the heap and owned, as opposed to a class member variable) is
giving me the chance to avoid const correctness.


A good book, maybe? And thinking about what to allow and what not to
allow in your own classes...


As I said I have no problems understanding the syntax and semantics. I
take the point on ownership and lifetime management though.

Thanks for you input,
quantdev2004

Oct 4 '05 #7
Victor Bazarov wrote:
[snip]
Unknown. Does 'Bar' *own* his copy of 'Foo', to which 'm_pBar' ... is
pointing? If it does own it, then you're probably right, the logic is
a bit screwed up. If it does not own it, it probably does not matter.

[snip]

I'd suggest that even if Bar does not *uniquely* own that Foo object,
it generally should still transfer its constness to the pointee.
Consider:

class Foo;

class Bar
{
Bar() : pFoo_( new Foo ) {}
~Bar() { delete pFoo_; }
// ...
private:
Foo* const pFoo;
};

Almost certainly, Bar uniquely owns the pointee of pFoo, and in such a
case, transferring the constness of Bar to pFoo should probably also
transfer it to the pointee of pFoo. (Exceptions to that transferring
rule might include caching mechanisms, semaphores, etc., which are
private and still preserve logical constness but not physical
constness.)

When it comes to shared ownership, I'd suggest the same sort of thing
should generally apply. Consider:

class A;

class B
{
B( A& a ) : a_( a ) {} // Obviously, B is not responsible
// for deleting a; possibly better
// would be to do some ref counting

void Const() const; // should a_ be modifiable here?
// ...

private:
A& a_;
};

With the same sort of exception cases (caching schemes etc.),
const-correctness seems to imply that *a_ should usually become const
inside B::Const() even though there is no unique ownership here.

In short, I think transferring constness to pointee members should be
the default in all cases and should be overridden with a mutable
extension. (Compare std::vector and arrays: the first is fully
const-correct as a member in a class, the second is not.)

Cheers! --M

Oct 4 '05 #8
mlimber wrote:
[snip]
With the same sort of exception cases (caching schemes etc.),
const-correctness seems to imply that *a_ should usually become const

[snip]

Correction: *a_ should be simply a_ since it is a reference.

Oct 4 '05 #9
>
To get the behavior you want, you can do something like this:

[...]
Thanks for your contribution. I will give a go to your DeepPtr class.


Unfortunately, the disabled copy constructor and assignment operator
mean that such a pointer cannot be used in a standard container.


But you wouldn't be able to use "normal" const pointers either, isn't
it?
quantdev2004

Oct 4 '05 #10
qu**********@yahoo.co.uk wrote:
[snip]
Unfortunately, the disabled copy constructor and assignment operator
mean that such a pointer cannot be used in a standard container.


But you wouldn't be able to use "normal" const pointers either, isn't
it?


The pointees of member pointers (wheter the pointers are const or
non-const) and the referees of member references all have the same
issue with const-correctness. (Is that what you are asking?)

Cheers! --M

Oct 5 '05 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
5047
by: Bolin | last post by:
Hi all, A question about smart pointers of constant objects. The problem is to convert from Ptr<T> to Ptr<const T>. I have look up and seen some answers to this question, but I guess I am too...
19
6804
by: Thomas Matthews | last post by:
Hi, Given a structure of pointers: struct Example_Struct { unsigned char * ptr_buffer; unsigned int * ptr_numbers; }; And a function that will accept the structure:
17
2630
by: codeslinger | last post by:
What is the point of the construct in the subject line? Why the use of two const labels? Does that do something different than const void *x? And what would void * const x indicate? Thanks in...
7
1855
by: Mark P | last post by:
The following compiles without error on four different platforms (Linux g++, Sun CC, HP aCC, Win Dev-C++) so I suspect it's ok, but I don't see why this isn't a const-related error. pB is a...
15
2082
by: Jiří Paleček | last post by:
Hello, I know the rules for const handling in C++, but I'd like to ask what is the "right" way to use them, eg. when is it appropriate to make a member function const? This came across this...
16
3144
by: hzmonte | last post by:
Correct me if I am wrong, declaring formal parameters of functions as const, if they should not be/is not changed, has 2 benefits; 1. It tells the program that calls this function that the...
6
8287
by: Spoon | last post by:
Hello, I don't understand why gcc barks at me in this situation: $ cat foo.c extern void func(const int * const list, int nent); int main(void) { int *p;
4
6670
by: grizggg | last post by:
I have searched and not found an answer to this question. I ran upon the following statement in a *.cpp file in a member function: static const char * const pacz_HTMLContentTypeHeader =...
3
2095
by: subramanian100in | last post by:
Consider the following program: #include <iostream> using namespace std; class Base { public: Base(int x = 0);
0
7064
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7315
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
6974
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
7445
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
5559
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development projectplanning, coding, testing,...
0
3158
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
3147
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
1492
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
1
721
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.