By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,819 Members | 1,173 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,819 IT Pros & Developers. It's quick & easy.

Question on constness

P: n/a
Hi all,

I have a class, call it Object of heap-allocated objects. They are
managed via a smart pointer class Ref (actually a template class but
that does not matter for the problem). Object instances are created
via a factory method that returns a Ref and all constructors are
protected.

My "problem" is the following. The Ref class is basically a pointer,
e.g. something like

class Ref {
public:
//... some methods.

private:
Object* ptr;
}

and it supports all the usual operations for smart pointers like *,
->, assignment -- is particular ptr is *not* const.

The constructor is, basically

(A)

Ref(Object* ptr) : ptr(ptr) {
//Do some stuff if this->ptr != 0.
}

Now, looking at the signature of the constructor, my first temptation
was to write

(B)

Ref(const Object* ptr) : ptr(ptr) {
//Do some stuff if this->ptr != 0.
}

Because in the "do some stuff" part I do *not* change in any way the
pointed to Object. But, of course, the compiler complains because I'm
assigning a const to a non const. So I was tempted to do

(C)

Ref(const Object* ptr) : ptr(const_cast<Object*>(ptr)) {
//Do some stuff if this->ptr != 0.
}

but that const_cast sure does leave me nervous.

The reason I want to make the signature of the Ref constructor as in
(B) is because a lot of methods create Ref's to their arguments but
otherwise do *not* change them, so, it seems to me, I should declare
them const but because of (A) I cannot. Any advice on this? Is (C) the
best solution? Am I failing to understand the meaning of const?

Best regards,
G. Rodrigues
Jul 23 '05 #1
Share this Question
Share on Google+
7 Replies


P: n/a
Gonçalo Rodrigues <op*****@mail.telepac.pt> wrote in
news:64********************************@4ax.com:
Hi all,

I have a class, call it Object of heap-allocated objects. They are
managed via a smart pointer class Ref (actually a template class but
that does not matter for the problem). Object instances are created
via a factory method that returns a Ref and all constructors are
protected.

My "problem" is the following. The Ref class is basically a pointer,
e.g. something like

class Ref {
public:
//... some methods.

private:
Object* ptr;
}

and it supports all the usual operations for smart pointers like *,
->, assignment -- is particular ptr is *not* const.

The constructor is, basically

(A)

Ref(Object* ptr) : ptr(ptr) {
//Do some stuff if this->ptr != 0.
}

Now, looking at the signature of the constructor, my first temptation
was to write

(B)

Ref(const Object* ptr) : ptr(ptr) {
//Do some stuff if this->ptr != 0.
}

Because in the "do some stuff" part I do *not* change in any way the
pointed to Object. But, of course, the compiler complains because I'm
assigning a const to a non const. So I was tempted to do
In a certain way of looking at it, you do. OK, you don't modify Object
within this function, but you do allow for some other function to modify
Object via the member variable ptr. The only way to make the argument a
const pointer would be to also make the member variable a const pointer.
If you can get a non-const pointer out of your Ref class (via operator*,
or operator-> for example), then you can't make your constructor
parameter non-const either. If you did, you'd be lying to the user of
the Ref class (semantically speaking). By making the parameter const,
you're promising to the user that the Ref class will not modify the
pointed-to Object, nor will it allow other users of the Ref class to
modify it either.
(C)

Ref(const Object* ptr) : ptr(const_cast<Object*>(ptr)) {
//Do some stuff if this->ptr != 0.
}

but that const_cast sure does leave me nervous.

The reason I want to make the signature of the Ref constructor as in
(B) is because a lot of methods create Ref's to their arguments but
otherwise do *not* change them, so, it seems to me, I should declare
them const but because of (A) I cannot. Any advice on this? Is (C) the
best solution? Am I failing to understand the meaning of const?


Sounds more like you're not entirely understanding your own design. If
you do B, then your Ref class should never have a way to get the non-
const pointer out of Ref. If you could, you could then write code such
as (assuming Ref were constructable without the factory...):

{
const Object abc;
Ref refobj(&abc);

*refobj = 45; // Undefined Behavior!!!
}

At that assignment, you'd be allowing a caller to modify a const object
via a non-const pointer. This is Undefined Behaviour and is "illegal".

Jul 23 '05 #2

P: n/a
* Gonçalo Rodrigues:

I have a class, call it Object of heap-allocated objects. They are
managed via a smart pointer class Ref (actually a template class but
that does not matter for the problem). Object instances are created
via a factory method that returns a Ref and all constructors are
protected.
[snip]
The reason I want to make the signature of the Ref constructor as in
(B) is because a lot of methods create Ref's to their arguments
Deal in Ref's only: if you mix in raw pointers you're asking for trouble.

but
otherwise do *not* change them, so, it seems to me, I should declare
them const but because of (A) I cannot. Any advice on this? Is (C) the
best solution? Am I failing to understand the meaning of const?


One solution is to let 'const' for a Ref mean 'const' for the referred
object.

class Ref
{
...
public:
Object* operator->() { return myPointer; }
Object const* operator->() const { return myPointer; }
};

If Ref is assignable then that may (just may) be impractical, because you
may then want to be able assign a reference to a const Object.

In that case, consider having two classes: Ref and ConstRef, where Ref
converts to ConstRef but not the other way. Then 'const' applies only to the
smartpointer itself, not the referred object.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #3

P: n/a
> Object instances are created via a factory method that returns a Ref
and all
constructors are protected.


Your object factory returns Refs? Smart pointers are supposed to be
local, i.e.

void myFunc()
{
Ref<MyClass> ptr( getMyClassFactory()->create("myClass") );
ptr->doSomething();

// when the function returns the ptr destructor automatically
// releases the MyClass instance.
}

If your factory returns a dynamically allocated smart pointer, that
defeats the point of using smart pointers.

-Aleko

Jul 23 '05 #4

P: n/a
On 2 Apr 2005 09:59:18 -0800, "aleko" <al**********@gmail.com> fed
this fish to the penguins:
Object instances are created via a factory method that returns a Ref

and all
constructors are protected.


Your object factory returns Refs? Smart pointers are supposed to be
local, i.e.

void myFunc()
{
Ref<MyClass> ptr( getMyClassFactory()->create("myClass") );
ptr->doSomething();

// when the function returns the ptr destructor automatically
// releases the MyClass instance.
}

If your factory returns a dynamically allocated smart pointer, that
defeats the point of using smart pointers.


I'm not sure of the correct terminology (I'm a relative newbie in
C++), but they are smart pointers with shared semantics. An instance
is destroyed when there are no more Ref's pointing to it. The Ref's
themselves are not dynamically allocated but passed and copied around.

Best regards,
G. Rodrigues
Jul 23 '05 #5

P: n/a
On Thu, 31 Mar 2005 15:45:48 GMT, Andre Kostur <nn******@kostur.net>
fed this fish to the penguins:
Gonçalo Rodrigues <op*****@mail.telepac.pt> wrote in
news:64********************************@4ax.com :
Hi all,

I have a class, call it Object of heap-allocated objects. They are
managed via a smart pointer class Ref (actually a template class but
that does not matter for the problem). Object instances are created
via a factory method that returns a Ref and all constructors are
protected.

My "problem" is the following. The Ref class is basically a pointer,
e.g. something like

class Ref {
public:
//... some methods.

private:
Object* ptr;
}

and it supports all the usual operations for smart pointers like *,
->, assignment -- is particular ptr is *not* const.

The constructor is, basically

(A)

Ref(Object* ptr) : ptr(ptr) {
//Do some stuff if this->ptr != 0.
}

Now, looking at the signature of the constructor, my first temptation
was to write

(B)

Ref(const Object* ptr) : ptr(ptr) {
//Do some stuff if this->ptr != 0.
}

Because in the "do some stuff" part I do *not* change in any way the
pointed to Object. But, of course, the compiler complains because I'm
assigning a const to a non const. So I was tempted to do


In a certain way of looking at it, you do. OK, you don't modify Object
within this function, but you do allow for some other function to modify
Object via the member variable ptr. The only way to make the argument a
const pointer would be to also make the member variable a const pointer.
If you can get a non-const pointer out of your Ref class (via operator*,
or operator-> for example), then you can't make your constructor
parameter non-const either. If you did, you'd be lying to the user of
the Ref class (semantically speaking). By making the parameter const,
you're promising to the user that the Ref class will not modify the
pointed-to Object, nor will it allow other users of the Ref class to
modify it either.


Thanks, I was not aware of this.
(C)

Ref(const Object* ptr) : ptr(const_cast<Object*>(ptr)) {
//Do some stuff if this->ptr != 0.
}

but that const_cast sure does leave me nervous.

The reason I want to make the signature of the Ref constructor as in
(B) is because a lot of methods create Ref's to their arguments but
otherwise do *not* change them, so, it seems to me, I should declare
them const but because of (A) I cannot. Any advice on this? Is (C) the
best solution? Am I failing to understand the meaning of const?


Sounds more like you're not entirely understanding your own design. If
you do B, then your Ref class should never have a way to get the non-
const pointer out of Ref. If you could, you could then write code such
as (assuming Ref were constructable without the factory...):

{
const Object abc;
Ref refobj(&abc);

*refobj = 45; // Undefined Behavior!!!
}

At that assignment, you'd be allowing a caller to modify a const object
via a non-const pointer. This is Undefined Behaviour and is "illegal".


Constructors are protected, so you never can instantiate a local
object and create a pointer to it - unless some derived class does it.
But hey, the code is under my control and has explicit comments: don't
do that or the whole Universe will collapse.

With your and A. Steinbach's input I'm trying to better my design.

Best regards,
G. Rodrigues
Jul 23 '05 #6

P: n/a
> An instance is destroyed when there are no more Ref's pointing to it.
The Ref's themselves are not dynamically allocated but passed and copied around.


Are you using reference counting in your Ref class to control the
lifetime of the objects created by your object factory? Sort of like
COM's AddRef/Release?
If so, that's fine for local objects, but I don't see how you can pass
these outside the function.

Ref<MyClass> &createObject() {
Ref<MyClass> ptr( getObjectFactory()->create("myClass");
return ptr; // wrong, ptr gets destroyed when you leave this
function
}

Hope this helps,
Aleko

Jul 23 '05 #7

P: n/a
Well, I don't understand something. Why do you return a reference to a
local object? I would do something like this:

Ref<MyClass> getAnObject()
{
Ref<MyClass> ref(getFactory()->getObject());
return ref;
}

The copy constructor of Ref would be called and the data would not be
lost. At least, it works with std::auto_ptr.

Regards,
Piotr Filip Mieszkowski

Jul 23 '05 #8

This discussion thread is closed

Replies have been disabled for this discussion.