C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Correct constness
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Vadim
Guest





PostPosted: Sat May 13, 2006 12:21 am    Post subject: Correct constness Reply with quote



I'm puzzled with the following simple scenario:

class Settings
{
public:
...
int GetValue() const;
void SetValue();
...
};

class ConfigManager
{
public:
...
Settings* GetSettings() const;

private:
Settings* s_;
};

Now, ConfigManager::GetSettings should return pointer to non-const
Settings, so caller can modify the settings. The question is whether
SetSettings itself should be const member or not?

Given the code above, it doesn't really matter, because it doesn't make
much difference (at least to me). Observable, non-observable state
etc... I couldn't find one srtrong argument for going one way or
another. I'm also reluctant having two different methods, one const and
another non-const.

Can anybody can give me a good reason for using (or not using) const?

Thanks,
Vadim


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Andrei Alexandrescu (See
Guest





PostPosted: Sat May 13, 2006 12:21 pm    Post subject: Re: Correct constness Reply with quote



Vadim wrote:
Quote:
I'm puzzled with the following simple scenario:

class Settings
{
public:
...
int GetValue() const;
void SetValue();
...
};

class ConfigManager
{
public:
...
Settings* GetSettings() const;

private:
Settings* s_;
};

Now, ConfigManager::GetSettings should return pointer to non-const
Settings, so caller can modify the settings. The question is whether
SetSettings itself should be const member or not?

Given the code above, it doesn't really matter, because it doesn't make
much difference (at least to me). Observable, non-observable state
etc... I couldn't find one srtrong argument for going one way or
another. I'm also reluctant having two different methods, one const and
another non-const.

Can anybody can give me a good reason for using (or not using) const?

I try to use const on a member whenever I can. It's a strong indication
about the object's invariant, and it helps checking the internals of the
class in addition to its clients.


Andrei

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Tomás
Guest





PostPosted: Sat May 13, 2006 9:21 pm    Post subject: Re: Correct constness Reply with quote



Quote:
Now, ConfigManager::GetSettings should return pointer to non-const
Settings, so caller can modify the settings. The question is whether
SetSettings itself should be const member or not?


I see it simply:

Does the member function alter any of the member objects? If so, make it
non-const (you actually don't have a choice). Otherwise, make it const.

Here's an example of code I'd write:

class Monkey {

char* p;

public:

Monkey( char* const arg_p ) : p(arg_p) {}

void SetValue( char const c ) const /* Yes, const! */
{
*p = c;
}

void ChangeObject ( char* const arg_p ) /* Non-const! */
{
p = arg_p;
}
};



-Tomás

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Dave Harris
Guest





PostPosted: Sun May 14, 2006 12:21 pm    Post subject: Re: Correct constness Reply with quote

worndown (AT) gmail (DOT) com (Vadim) wrote (abridged):
Quote:
Now, ConfigManager::GetSettings should return pointer to non-const
Settings, so caller can modify the settings.

That's debatable - it depends on whether the Settings are "part of" the
ConfigManager. Usually member variables like s_ do represent a "part of"
relationship, especially if they are "owning" (eg the ConfigManager is
responsible for deleting the settings). You don't show enough code for me
to be sure. The word "Manager", when used as a class name, can be a bit
vague.

If X is const, then anything which is part of X should also be const. So
for const-correctness you need to think carefully about what relationships
your pointers are implementing.


Quote:
The question is whether SetSettings itself should be const member
or not?

It should not be const. The choice of which Settings the ConfigManager
uses is surely part of the visible state of the ConfigManager, and a
member function which changes the visible state should not be const.


Quote:
Given the code above, it doesn't really matter, because it doesn't make
much difference (at least to me).

Is that because you will never actually have a reference to a const
ConfigManager object?

You should find the code:

void ConfigManager::SetSettings( Settings *s ) const {
s_ = s;
}

will not compile, which is surely a clue.

-- Dave Harris, Nottingham, UK.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Ralf Fassel
Guest





PostPosted: Sun May 14, 2006 12:21 pm    Post subject: Re: Correct constness Reply with quote

* "Tomás" <NULL (AT) NULL (DOT) NULL>
| void SetValue( char ... c ) const /* Yes, const! */

[edit to clarify which 'const' we are talking about]

This is a design question. If the class is about the pointer, then
const is ok. But if the class is really about what the pointer points
to, the const is not adequate, even if the class is _formally_ not
changed by a call to SetValue. Dewhurst suggests in his C++-Gotchas
to couple 'const' to the logical state of the class, and I tend to
agree here...

R'

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Joshua Lehrer
Guest





PostPosted: Mon May 15, 2006 12:22 am    Post subject: Re: Correct constness Reply with quote

Tomás wrote:
Quote:
Here's an example of code I'd write:

class Monkey {

char* p;

public:

Monkey( char* const arg_p ) : p(arg_p) {}

void SetValue( char const c ) const /* Yes, const! */
{
*p = c;
}


I disagree. This precludes you from changing the data member 'p' to be
a const-correct class, like an std::string.

I like to make my member functions const if they do not change the
observable value of the class, and non-const if they do. In this case,
SetValue clearly changes the observable value of the class and should
not be const.

Do you really want this to compile?

const Monkey m(p);
m.SetValue('C');

joshua lehrer
http://www.lehrerfamily.com/


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Manfred von Willich
Guest





PostPosted: Mon May 15, 2006 12:22 am    Post subject: Re: Correct constness Reply with quote

You need to clarify the semantics of the external view of the class and
the methods, and the rest should follow.

Firstly, does the class semantically contain (as opposed to refer to)
the Settings object, as for example the data content of a "string" or
"vector" type? From the naming and your description, this does not
appear to be the intent. Accordingly, the SetSettings would also be
const if it does not change the ConfigManager object itself (i.e. if
the compiler does not complain), as you are not semantically modifying
its content, only what it refers to.

Secondly, you have not made it clear what SetSettings will do, as this
will affect its constness. It seems unlikely that it is to copy a
Settings into the Settings object pointed to by s_, since the
appropriate way of doing this from your description of GetSettings is
that you would do that as
*setmng.GetSettings() = SomeSettings;
or
setmng.GetSettings()->SetValue();
and a SetSettings should be removed. If SetSettings is supposed to set
the member pointer s_, then it clearly cannot be const.

Incidentally, I use the convention where possible for a
parameter/return type that a pointer implies a transfer of ownership,
and a reference implies no transfer. Accordingly, I would have changed
your GetSettings to
Settings& GetSettings() const { return *s_; }


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Gene Bushuyev
Guest





PostPosted: Mon May 15, 2006 12:22 am    Post subject: Re: Correct constness Reply with quote

"Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail (AT) erdani (DOT) org>
wrote in message news:44652BCB.30101 (AT) erdani (DOT) org...
Quote:
Vadim wrote:
I'm puzzled with the following simple scenario:

class Settings
{
public:
...
int GetValue() const;
void SetValue();
...
};

class ConfigManager
{
public:
...
Settings* GetSettings() const;

private:
Settings* s_;
};

Now, ConfigManager::GetSettings should return pointer to non-const
Settings, so caller can modify the settings. The question is whether
SetSettings itself should be const member or not?

Given the code above, it doesn't really matter, because it doesn't make
much difference (at least to me). Observable, non-observable state
etc... I couldn't find one srtrong argument for going one way or
another. I'm also reluctant having two different methods, one const and
another non-const.

Can anybody can give me a good reason for using (or not using) const?

I try to use const on a member whenever I can. It's a strong indication
about the object's invariant, and it helps checking the internals of the
class in addition to its clients.

Good point. Another reason to separate accessors and mutators is for the
purposes of encapsulation and information hiding. Functions that return
non-const references/pointers to internal data are almost as bad as making that
data public. The loosest coupling is provided by accessor functions that return
by value, which should always be preferred unless prohibitively expensive. There
is also a question of exception safety. Often accessors can provide higher
exception guarantee than mutators.

--
Gene Bushuyev (www.gbresearch.com)
----------------------------------------------------------------
There is no greatness where there is no simplicity, goodness and truth. ~ Leo
Tolstoy


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
James Dennett
Guest





PostPosted: Mon May 15, 2006 12:22 am    Post subject: Re: Correct constness Reply with quote

Tomás wrote:
Quote:
Now, ConfigManager::GetSettings should return pointer to non-const
Settings, so caller can modify the settings. The question is whether
SetSettings itself should be const member or not?


I see it simply:

Does the member function alter any of the member objects? If so, make it
non-const (you actually don't have a choice). Otherwise, make it const.

Here's an example of code I'd write:

class Monkey {

char* p;

public:

Monkey( char* const arg_p ) : p(arg_p) {}

void SetValue( char const c ) const /* Yes, const! */
{
*p = c;
}

void ChangeObject ( char* const arg_p ) /* Non-const! */
{
p = arg_p;
}
};

That's too simplistic to give the best results. If
std::string followed these rules, the only non-const
operations might be those that potentially changed
its size, and this also exposes too much in the way
of implementation details. For "pimpl" classes, it
would make almost every operation const, whereas it
makes much more sense for the const-ness of operations
on the pimpl/handle to match the const-ness of the
operations on the body. Physical design ought not
to have unfortunate effects on interfaces.

The rule you state puts const on operations that can
change the object's state (which is bad), and it fails
to put const on operations that don't affect the
logical state of the object (such as those which
might update an internal cache).

Without knowing what 'p' points to in your "example"
above, it's hard to say for sure that it's an example
of bad design, but it certainly gives cause for concern,
and wouldn't pass any code review I've seen.

-- James

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Vadim
Guest





PostPosted: Mon May 15, 2006 12:22 am    Post subject: Re: Correct constness Reply with quote

Thanks for the reply, but I don't think this is what I was asking
about.

If I rewrite my example this way:

class Settings
{
...
int GetValue() const;
void SetValue(int v);
};

class ConfigManager
{
....
const Settings* GetSettings() const;
Settings* GetSettings();
};

then it makes more sense to me. Seems that it was impossible to
accomplish with one SetSettings function. I'm taking my question back.

Vadim


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Tomás
Guest





PostPosted: Mon May 15, 2006 12:22 am    Post subject: Re: Correct constness Reply with quote

Tomás posted:


Quote:
I see it simply:

Does the member function alter any of the member objects? If so, make it
non-const (you actually don't have a choice). Otherwise, make it const.

I take that back. I was writing a class today which had dynamic memory
allocation, and I made a certain member function non-const even though I
it didn't alter any member objects (it did however alter memory which I
had dynamically allocated for an object of the class).

Something akin to the following:

class SomeClass {

unsigned char *p;
/* Address of dynamically allocated memory */


void SetSecondByte(unsigned char const val)
{
p[1] = val;
}
};


-Tomás

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
wrybred
Guest





PostPosted: Mon May 15, 2006 12:22 am    Post subject: Re: Correct constness Reply with quote

Vadim wrote:
Quote:
I'm puzzled with the following simple scenario:

class Settings
{
public:
...
int GetValue() const;
void SetValue();
...
};

class ConfigManager
{
public:
...
Settings* GetSettings() const;

private:
Settings* s_;
};

Now, ConfigManager::GetSettings should return pointer to non-const
Settings, so caller can modify the settings. The question is whether
SetSettings itself should be const member or not?

Given the code above, it doesn't really matter, because it doesn't make
much difference (at least to me). Observable, non-observable state
etc... I couldn't find one srtrong argument for going one way or
another. I'm also reluctant having two different methods, one const and
another non-const.

Can anybody can give me a good reason for using (or not using) const?

Do you really want settings to be changed by anyone at any time, by
virtue of exposing GetSettings()?

Const-correctness: really, just do it. Don't think about it. You've
insulated yourself from the problems that plague modern systems, such
as security, concurrency, and need to support legacy clients dependent
on a format you later regret exposing.

So setting aside the question of const-correctness, there are two
deeper design decisions:
1. Do you want to hard-code configuration values in a structure, even
if it's semi-opaque?
2. Do you want to give piecewise access to setting configuration
values?

1. If your system is fairly static, it's reasonable to have hard-coded
settings. If things are likely to change, then a dynamic API, using
something like Boost properties or a container of boost::any will give
more flexibility and less rework when the need arises for a new value.

2. Piecewise mutation of configuration values is very dangerous. It
allows clients to set things as they see fit, mucking with assumptions
that others make. Better to think in terms of a group of special
clients, such as a command line reader, XML configuratiion reader,
network-based daemon, etc., that can modify things. Then provide an
interface suitable for them and unsuitable for the rest of the world
that might be tempted to hack their way for their own ends.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Gene Bushuyev
Guest





PostPosted: Mon May 15, 2006 12:21 pm    Post subject: Re: Correct constness Reply with quote

"Vadim" <worndown (AT) gmail (DOT) com> wrote in message
news:1147554969.226233.308290 (AT) d71g2000cwd (DOT) googlegroups.com...
Quote:
Thanks for the reply, but I don't think this is what I was asking
about.

If I rewrite my example this way:

class Settings
{
...
int GetValue() const;
void SetValue(int v);
};

class ConfigManager
{
....
const Settings* GetSettings() const;

either this or better yet:

Settings GetSettings() const; // throw() if possible

And why would your class use the pointers at all?

Quote:
Settings* GetSettings();

this is not an accessor! Not only the name is confusing, but it also blows up
encapsulation; the ConfigManager surrendered all rights on its own Settings
object. Think about something like:

void SetSettings(const Settings&);

This is a contrived example, so the answers are conditioned on that. In many
cases the presence of getters/setters is an indication of poor design decisions:
the class doesn't sufficiently own its members.

--
Gene Bushuyev (www.gbresearch.com)
----------------------------------------------------------------
There is no greatness where there is no simplicity, goodness and truth. ~ Leo
Tolstoy


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Vadim
Guest





PostPosted: Mon May 15, 2006 12:21 pm    Post subject: Re: Correct constness Reply with quote

Quote:
Firstly, does the class semantically contain (as opposed to refer to)
the Settings object, as for example the data content of a "string" or
"vector" type? From the naming and your description, this does not
appear to be the intent.

My bad, I have to be more specific. ConfigManager and Settings were
random examples that came to my mind. In reality ConfigManager have a
different name and it represents network connectivity configuration
(configuration itself is serialized/deserialized to/from XML file).
Among other things it allows to specify usage of a proxy server. Think
of a a DLL (ownership transfer is not appropriate in this case) which
looks like this:

/* header file */

class IProxy
{
public:
...
uint16 GetPort() const = 0;
void SetPort(uint16 port) = 0;
void AddRef() const = 0;
void Release() const = 0;
...
};

class INetConfig
{
public:
....
IProxy* GetProxy() const = 0;
void AddRef() const = 0;
void Release() const = 0;
....
};

__declspec(dllexport) INetConfig* GetNetConfig();

/* end of header */

The only exported function is GetNetConfig through which caller can get
a pointer to INetConfig and read/change proxy settings. There's no
separate SetProxy. Proxy's settings are changed through pointer to
IProxy (SetPort method, for example).

Does INetConfig semantically contain IProxy? Hard to tell. Yes and no,
IMO. If I knew for sure, it would be easier for me to decide whether
GetProxy should be const or not. I did it const, as shown in example
above, but wasn't totally comfortable with it. I feel that IProxy is
part of INetConfig semantically and by changing proxy settings
INetConfig is changing as well...

This was my original question - whether INetConfig::GetProxy should be
const or not? It will compile and work in both cases: const and
non-const. However, since right now I don't have a strong opinion on
this, I wanted to develop one so I can follow it in the future when
encounter similar situation again.

Vadim


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Tomás
Guest





PostPosted: Mon May 15, 2006 12:21 pm    Post subject: Re: Correct constness Reply with quote

Quote:
I see it simply:

Does the member function alter any of the member objects? If so, make it
non-const (you actually don't have a choice). Otherwise, make it const.


I take that back. I wrote code a class the other day that had a member
function which altered dynamically allocated memory, and I declared the
function non-const.


-Tomás

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.