Topic: const and ctor
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: 1995/04/06 Raw View
I tend to run across a case that either needs or could be radically
simplified by the presence of cv-qualified constructors every few
months. So I have been a little surprised at the lack of good concrete
examples posted on this subject.
I have found that the uses fall broadly into two categories:
/1/ optimisation
/2/ supporting objects with reference/proxy behaviour
In the first case, consider a class that describes objects that internally
use a resource, such as a lookup table, for part of their implementation. In
the non-const version this table may be modified, whereas the const version
will leave it unchanged from the default. It would be possible for a
const aware constructor to reference a shared static table, whereas the
non-const version would own its own copy. Note that this differs in intention
from the handle-body idiom. Other examples include not setting up optimisation
caches for recent changes or change logs, etc.
Const distinction for pointer-like objects, such as iterators, is
expressed using different classes. This is necessary as there are two
kinds of constness: the constness of the target and the constness of the
iterator itself. For references, the object is bound once to its
referand at the beginning of its lifecycle and the constness of the
reference reflects the constness of access to its referand. This latter
requirement can only sensibly be handled w/ cv-qualified constructors.
A simple example of this is a string dummy class that offers operations
on a raw C string (as posted earlier this thread), eg.
class raw_string
{
public:
// leave range checking aside for the moment
const raw_string(const char *);
raw_string(char *);
const raw_string(const raw_string &);
raw_string(raw_string &);
... // subset of standard string operations
};
Sure, this won't protect you from changing what is aliased outside of this
object, to answer a point Pete made. But that is, unfortunately, not related
to the subject of this thread. You can get that 'problem' with pointers in
C, you don't need C++ and constructors to do that.
One example that cannot be expressed any other way is a hierarchy where
a subview of the base class is part of the hierarchy, eg. strings and
substrings, and arrays and subarrays:
/* abstract */ class string
{
public:
...
};
class sub_string : public string
{
public:
const sub_string(const string &);
sub_string(string &);
...
};
class some_string : public string
{
public:
...
const sub_string operator()(size_t, size_t) const;
sub_string operator()(size_t, size_t);
const sub_string operator()(size_t) const;
sub_string operator()(size_t);
...
};
... // other implementations of string
Try rewriting this example w/o cv-qualified constructors so that it
correctly preserves const _and_ substitutability. Tough isn't it?
[NB. Alternatively const inheritance would provide a partial solution,
but that's not allowed at the moment either :-)]
Any further thoughts on this?
+---------------------------+-------------------------------------+
| Kevlin A P Henney | Can you secure Christmas with an |
| kevlin@wslint.demon.co.uk | approximation only eighteen million |
| Westinghouse Systems Ltd | seconds left of the original old |
| | red chimney? - Jack Kerouac |
+---------------------------+-------------------------------------+
Author: wikman@king.trs.ntc.nokia.com (Johan Wikman)
Date: 1995/04/04 Raw View
>>>>> "Pete" == Pete Becker <pete@borland.com> writes:
Pete> The problem is that the ability to treat a non-const object as a
Pete> const object is deeply ingrained in the C++ type system. Making
Pete> local changes in the way we can create classes doesn't change
Pete> this fundamental design decision.
Pete> -- Pete
Precisely what I detected when I attempted to produce a meaningful
example...
Johan
--
--
johan.wikman@ntc.nokia.com; C=FI,A=Elisa,P=Nokia Telecom,S=Wikman,Gi=Johan
TL4E - P.P. Box 12, SF-02611 Espoo 61, Finland
Author: pete@borland.com (Pete Becker)
Date: 1995/04/01 Raw View
In article <6572@bigfoot.first.gmd.de>, chu@prosun.first.gmd.de (Vladimir Chukharev) says:
>
>In article <3l7g5s$2g2@druid.borland.com>, pete@borland.com (Pete Becker) writes:
>|> In article <PRANGE.95Mar27151834@slbwa7.bln.sel.alcatel.de>, prange@slbwa7.bln.sel.alcatel.de (Martin Prange) says:
>|> >[ deleted.. ]
>|> >
>|> >> Can someone post an example of some meaningful code that would be
>|> > ===================
>|> >>written significantly differently in the presence of such a new rule? Or
>|> >>is this simply a case of orthogonality for its own sake?
>|> >> -- Pete
>|> >
>|> >Sure I can [ .... and will do so :) ]
>|> >
>|> >Given the case of a String class:
>|> >
>|> >class String {
>|> > bool allocated;
>|> > unsigned len;
>|> > char *ptr;
>|> >public:
>|> > String(const char* s)
>|> > : allocated(YES),
>|> > len(strlen(s)),
>|> > ptr(0)
>|> > { ptr= new char[len]; };
>|> >
>|> > const String(const char* s)
>|> > : allocated(NO),
>|> > len(strlen(s)),
>|> > ptr(s)
>|> > {
>|> >[ deleted.. ]
>|> > }
>|> Using this string class and its const constructor:
>|>
>|> int main()
>|> {
>|> char data[20];
>|> strcpy( data, "Testing" );
>|> const String s(data);
> ^^^^
>Oops! 'char*' passed as 'const char*'
Not "Oops". It is perfectly legal, and one of the fundamentals
of the type system. And it's precisely the reason that this attempt at
formulating the meaning of const constructors fails.
-- Pete
>
>|> strcpy( data, "Still testing" );
>|> // surprise! The pre-calculated hash is no longer valid...
>|> }
>|>
Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: 1995/03/30 Raw View
In article <3kqcvl$kk@druid.borland.com> pete@borland.com "Pete Becker" writes:
> Can someone post an example of some meaningful code that would be
>written significantly differently in the presence of such a new rule? Or
>is this simply a case of orthogonality for its own sake?
> -- Pete
Sure. Better support for smart references/proxies/surrogates. The
cv-qualification of such objects reflects the cv-qualification of their
referands -- as opposed to smart pointers and iterators where the constness
refers to the referee itself, and a separate class must be used to
express the constness of the target (eg. vector<T>::iterator vs
vector<T>::const_iterator).
Such an example would be a wrapper class for raw char *. This class would
provide a number of the standard non-length altering string ops on a
given char *. This can be used where complete/external control of the
char array is required, or for mixed language programming. It's a good
example of wrapping up a low level object w/ a high level interface.
Leaving out the bounds checking, such a class might be written:
class string_alias
// convenience wrapper for a given char array
{
public:
const string_alias(const char *);
string_alias(char *);
const string_alias(const string_alias &);
string_alias(string_alias &);
...
};
Some sample decls:
const char *cp = ...;
char *p = ...;
const string_alias cacp = cp; // OK
const string_alias cap = p; // OK
string_alias acp = cp; // Illegal
string_alias ap = p; // OK
Using this technique we can ensure statically that the constness of the
target is preserved throughout the lifetime of the referring object.
Any thoughts?
+---------------------------+-------------------------------------+
| Kevlin A P Henney | Can you secure Christmas with an |
| kevlin@wslint.demon.co.uk | approximation only eighteen million |
| Westinghouse Systems Ltd | seconds left of the original old |
| | red chimney? - Jack Kerouac |
+---------------------------+-------------------------------------+
Author: pete@borland.com (Pete Becker)
Date: 1995/03/30 Raw View
In article <PRANGE.95Mar29151533@slbwa7.bln.sel.alcatel.de>, prange@slbwa7.bln.sel.alcatel.de (Martin Prange) says:
>In this example:
>
>The additional String(char*) constructor is just a hack to prevent
>non-const C-Strings to match the arglist for String(const char*) !
>
>This cannot be a REAL solution.
>
Well, it almost has to be. Fundamental to C++ is the notion that
you can call const functions on non-const objects. That is, the meaning
of const here is that the function does not modify the object. It does not
mean that it can only be called on non-modifiable objects. Changing this
would be a major change, and looks to me like the only way to get to the
semantics that are being urged here. In the absence of such a change, I
don't see that being able to designate a different constructor for const
objects gains much.
-- Pete
Author: pete@borland.com (Pete Becker)
Date: 1995/03/30 Raw View
In article <796566202snz@wslint.demon.co.uk>, kevlin@wslint.demon.co.uk (Kevlin Henney) says:
>
>In article <3kqcvl$kk@druid.borland.com> pete@borland.com "Pete Becker" writes:
>
>> Can someone post an example of some meaningful code that would be
>>written significantly differently in the presence of such a new rule? Or
>>is this simply a case of orthogonality for its own sake?
>> -- Pete
>
>Sure. Better support for smart references/proxies/surrogates. The
>cv-qualification of such objects reflects the cv-qualification of their
>referands -- as opposed to smart pointers and iterators where the constness
>refers to the referee itself, and a separate class must be used to
>express the constness of the target (eg. vector<T>::iterator vs
>vector<T>::const_iterator).
>
>Such an example would be a wrapper class for raw char *. This class would
>provide a number of the standard non-length altering string ops on a
>given char *. This can be used where complete/external control of the
>char array is required, or for mixed language programming. It's a good
>example of wrapping up a low level object w/ a high level interface.
>Leaving out the bounds checking, such a class might be written:
>
> class string_alias
> // convenience wrapper for a given char array
> {
> public:
> const string_alias(const char *);
> string_alias(char *);
> const string_alias(const string_alias &);
> string_alias(string_alias &);
> ...
> };
>
>Some sample decls:
>
> const char *cp = ...;
> char *p = ...;
> const string_alias cacp = cp; // OK
> const string_alias cap = p; // OK
> string_alias acp = cp; // Illegal
> string_alias ap = p; // OK
>
>Using this technique we can ensure statically that the constness of the
>target is preserved throughout the lifetime of the referring object.
>
const string_alias fake( const char *s )
{
const string_alias result( s );
return result;
}
char text[] = "Hello, world!";
const string_alias doesnt_work = fake( text );
strcpy( text, "Fooled you!" );
The problem is that the ability to treat a non-const object as a const object
is deeply ingrained in the C++ type system. Making local changes in the
way we can create classes doesn't change this fundamental design
decision.
-- Pete
Author: cpp@netcom.com (Robin Rowe)
Date: 1995/03/30 Raw View
I gave it some more thought and experimentation. It would be
interesting to be able to do this:
const String& ref="Hello World";
The code below approximates what I had in mind. I wrote this today,
so I haven't decided yet whether this is good or useful. Opinions?
#include <iostream.h>
class String;
class StringHandle
{ const char* buffer;
public:
StringHandle(const char* buffer)
: buffer(buffer)
{}
operator const String&()
{ return (const String&) buffer;
} };
class String
{ char* buffer;
public:
void Say()
{ cout<<buffer<<" non-const\n";
}
void Say() const
{ cout<<buffer<<" const\n";
} };
int main()
{ const char* cstring="Hello";
const String& ref=(const String&) StringHandle(cstring);
const String& ref2=StringHandle("World");
// const String& ref3="Hello World"; // impossible.
ref.Say();
ref2.Say();
return 0;
}
/* output:
Hello const
World const
*/
Robin
--
-----
Robin Rowe cpp@netcom.com 408-626-6646 Carmel, CA
Rowe Technology C++ Design/Training Email for sample C++ Newsletter!
Author: prange@slbwa7.bln.sel.alcatel.de (Martin Prange)
Date: 1995/03/29 Raw View
In article <3l7g5s$2g2@druid.borland.com> pete@borland.com (Pete Becker) writes:
>
>Using this string class and its const constructor:
>
> int main()
> {
> char data[20];
> strcpy( data, "Testing" );
> const String s(data);
> strcpy( data, "Still testing" );
> // surprise! The pre-calculated hash is no longer valid...
> }
>
>Here's another:
>
> int main()
> {
> char *data = new char[20];
> const String s(data);
> delete [] data;
> // surprise! The string now contains a dangling pointer...
> }
>
> -- Pete
Sure ,... you are right. Sigh.
I forgot to include:
String(char* s)
: allocated(YES),
len(strlen(s)),
ptr(0)
{
ptr= new char[len+1];
memcpy(ptr,s,len+1);
};
BUT:
The real problem is, that none of the argument patterns ( like const String& )
_detect_ the _real_ constness of a type, it just _determines_ the way
constness is propagated _into_ a function or method.
In this example:
The additional String(char*) constructor is just a hack to prevent
non-const C-Strings to match the arglist for String(const char*) !
This cannot be a REAL solution.
So what we need for than problem is anything like a "noalias" or "restricted" attribute.
Another example ( just to make the things a little bit clearer) :
I traverse a collection:
const HashDictionary dict= functReturningDict();
Iterator i(dict);
Here the Iterator has to keep track of changes made to the collection,
ignore them ( and fail ), or simply lock the collection.
An Iterator, which gets a really_const dict ( that means, without a
possible non-const access from any other code chunk ! ) can make
optimization assumptions about this:
It simply can rely on this information, without checking the collection,
or registering iterators, locking it( which ist itself a non-const function)
,... etc... (add your own coding-problems here)...
Assumptions like these stated above could speed up production code
without(!) making them unreliable.
-- Martin
--
-- % ---------------------------------------------------------------%_|_|_|+
/ prange@sel.bln.alcatel.de Alcatel-SEL Berlin |_|_|
\\ If you believe, the opinions expressed here are mine --- _|_|
\\__ you got it ! ______________________________________________|_|
Author: cpp@netcom.com (Robin Rowe)
Date: Wed, 29 Mar 1995 05:04:51 GMT Raw View
Pete,
<< Can someone post an example of some meaningful code that would
be written significantly differently in the presence of such a new rule?
Or is this simply a case of orthogonality for its own sake? >>
What I had in mind when I started this thread was that objects that would
normally require a deep copy in the constructor might be made with a shallow
copy if they were const. The C++ language design seems to prevent this,
and I wondered why. I wasn't asking for a new feature, just wondering why
the existing rules were designed to prevent it.
I wanted to be able to make const Strings out of static c strings without
a deep copy.
Robin
--
-----
Robin Rowe cpp@netcom.com 408-626-6646 Carmel, CA
Rowe Technology C++ Design/Training Email for sample C++ Newsletter!
Author: prange@slbwa7.bln.sel.alcatel.de (Martin Prange)
Date: Tue, 28 Mar 1995 15:35:03 GMT Raw View
[ deleted.. ]
> Can someone post an example of some meaningful code that would be
===================
>written significantly differently in the presence of such a new rule? Or
>is this simply a case of orthogonality for its own sake?
> -- Pete
Sure I can [ .... and will do so :) ]
Given the case of a String class:
class String {
bool allocated;
unsigned len;
char *ptr;
public:
String(const char* s)
: allocated(YES),
len(strlen(s)),
ptr(0)
{ ptr= new char[len]; };
const String(const char* s)
: allocated(NO),
len(strlen(s)),
ptr(s)
{
// Here I can make decisions like:
-- NO MEMORY WILL NEED TO BE ALLOCATED ( const )
or
-- hash codes can be precalculated instead of beeing calculated at runtime...
-- anything else meaningful...
};
void ~String(void)
{
if ( allocated )
delete ptr;
};
const char* operator(void) const { return ptr; };
String operator+=(const String& s);
};
BETTER:
If we could detect the *staticness* of a primitive(e.g.):
[...]
const String(static const char* s)
: allocated(NO),
len(strlen(s)),
ptr(s)
{}; // no memory allocation nescessary, memory will be read-only
// and CANNOT run out of scope!!!
[...]
&&&&&&&&&&&&&&&&&&----------------------------
What do we all lean from this chunk of code:
We need a CONST DESTRUCTOR also ! ( hooray .... !!! )
Have fun!
Martin Prange
--
-- % ---------------------------------------------------------------%_|_|_|+
/ prange@sel.bln.alcatel.de Alcatel-SEL Berlin |_|_|
\\ If you believe, the opinions expressed here are mine --- _|_|
\\__ you got it ! ______________________________________________|_|
Author: pete@borland.com (Pete Becker)
Date: 27 Mar 1995 23:02:20 GMT Raw View
In article <PRANGE.95Mar27151834@slbwa7.bln.sel.alcatel.de>, prange@slbwa7.bln.sel.alcatel.de (Martin Prange) says:
>
>
>>In article <WIKMAN.95Mar22124712@king.trs.ntc.nokia.com>, wikman@king.trs.ntc.nokia.com (Johan Wikman) says:
>>>
>>>
>>>>>>>> "Ed" == Ed Osinski <osinski@merv.cs.nyu.edu> writes:
>>>
>>>Ed> It's too bad that constructors can't be const. There have been a number of
> ===============
>>>Ed> times that I've wanted const objects to be constructed with different
>>>Ed> parameters than non-const objects; for example:
>>>
>>>Ed> class C;
>>>
>>>Ed> class D {
>>>Ed> public:
>>>Ed> D (C *);
>>>Ed> const D (const C *);
>>>Ed> ...
>>>Ed> };
>>>
>
>[ deleted.. ]
>
>> Can someone post an example of some meaningful code that would be
> ===================
>>written significantly differently in the presence of such a new rule? Or
>>is this simply a case of orthogonality for its own sake?
>> -- Pete
>
>
>Sure I can [ .... and will do so :) ]
>
>Given the case of a String class:
>
>class String {
> bool allocated;
> unsigned len;
> char *ptr;
>public:
> String(const char* s)
> : allocated(YES),
> len(strlen(s)),
> ptr(0)
> { ptr= new char[len]; };
>
> const String(const char* s)
> : allocated(NO),
> len(strlen(s)),
> ptr(s)
> {
> // Here I can make decisions like:
> -- NO MEMORY WILL NEED TO BE ALLOCATED ( const )
> or
> -- hash codes can be precalculated instead of beeing calculated at runtime...
> -- anything else meaningful...
> };
>
> void ~String(void)
> {
> if ( allocated )
> delete ptr;
> };
>
> const char* operator(void) const { return ptr; };
> String operator+=(const String& s);
>};
>
Using this string class and its const constructor:
int main()
{
char data[20];
strcpy( data, "Testing" );
const String s(data);
strcpy( data, "Still testing" );
// surprise! The pre-calculated hash is no longer valid...
}
Here's another:
int main()
{
char *data = new char[20];
const String s(data);
delete [] data;
// surprise! The string now contains a dangling pointer...
}
-- Pete
Author: pete@borland.com (Pete Becker)
Date: 27 Mar 1995 23:04:12 GMT Raw View
In article <WIKMAN.95Mar27120414@king.trs.ntc.nokia.com>, wikman@king.trs.ntc.nokia.com (Johan Wikman) says:
>
>
>>>>>> "PB" == Pete Becker <pete@borland.com> writes:
>
>PB> Can someone post an example of some meaningful code that would be
>PB> written significantly differently in the presence of such a new rule? Or
>PB> is this simply a case of orthogonality for its own sake?
>PB> -- Pete
>
>I thought I had a few good examples. But when I was about to post them
>here, I realized that they were no-good. So, I fail to come up with
>meaningful code that would show that const constructors would truly be
>useful. Perhaps they aren't...
>
This is often the case. There's nothing like trying to write some
code to point out the issues that haven't been considered. I don't claim
there's no benefit from const constructors, 'cause I haven't thought much
about them. But I also don't see what these benefits would be.
-- Pete
Author: prange@slbwa7.bln.sel.alcatel.de (Martin Prange)
Date: Mon, 27 Mar 1995 13:18:34 GMT Raw View
>In article <WIKMAN.95Mar22124712@king.trs.ntc.nokia.com>, wikman@king.trs.ntc.nokia.com (Johan Wikman) says:
>>
>>
>>>>>>> "Ed" == Ed Osinski <osinski@merv.cs.nyu.edu> writes:
>>
>>Ed> It's too bad that constructors can't be const. There have been a number of
===============
>>Ed> times that I've wanted const objects to be constructed with different
>>Ed> parameters than non-const objects; for example:
>>
>>Ed> class C;
>>
>>Ed> class D {
>>Ed> public:
>>Ed> D (C *);
>>Ed> const D (const C *);
>>Ed> ...
>>Ed> };
>>
[ deleted.. ]
> Can someone post an example of some meaningful code that would be
===================
>written significantly differently in the presence of such a new rule? Or
>is this simply a case of orthogonality for its own sake?
> -- Pete
Sure I can [ .... and will do so :) ]
Given the case of a String class:
class String {
bool allocated;
unsigned len;
char *ptr;
public:
String(const char* s)
: allocated(YES),
len(strlen(s)),
ptr(0)
{ ptr= new char[len]; };
const String(const char* s)
: allocated(NO),
len(strlen(s)),
ptr(s)
{
// Here I can make decisions like:
-- NO MEMORY WILL NEED TO BE ALLOCATED ( const )
or
-- hash codes can be precalculated instead of beeing calculated at runtime...
-- anything else meaningful...
};
void ~String(void)
{
if ( allocated )
delete ptr;
};
const char* operator(void) const { return ptr; };
String operator+=(const String& s);
};
BETTER:
If we could detect the *staticness* of a primitive(e.g.):
[...]
const String(static const char* s)
: allocated(NO),
len(strlen(s)),
ptr(s)
{}; // no memory allocation nescessary, memory will be read-only
// and CANNOT run out of scope!!!
[...]
&&&&&&&&&&&&&&&&&&----------------------------
What do we all lean from this chunk of code:
We need a CONST DESTRUCTOR also ! ( hooray .... !!! )
Have fun!
Martin Prange
--
-- % ---------------------------------------------------------------%_|_|_|+
/ prange@sel.bln.alcatel.de Alcatel-SEL Berlin |_|_|
\\ If you believe, the opinions expressed here are mine --- _|_|
\\__ you got it ! ______________________________________________|_|
--
-- % ---------------------------------------------------------------%_|_|_|+
/ prange@sel.bln.alcatel.de Alcatel-SEL Berlin |_|_|
\\ If you believe, the opinions expressed here are mine --- _|_|
\\__ you got it ! ______________________________________________|_|
Author: wikman@king.trs.ntc.nokia.com (Johan Wikman)
Date: 27 Mar 1995 09:04:14 GMT Raw View
>>>>> "PB" == Pete Becker <pete@borland.com> writes:
PB> Can someone post an example of some meaningful code that would be
PB> written significantly differently in the presence of such a new rule? Or
PB> is this simply a case of orthogonality for its own sake?
PB> -- Pete
I thought I had a few good examples. But when I was about to post them
here, I realized that they were no-good. So, I fail to come up with
meaningful code that would show that const constructors would truly be
useful. Perhaps they aren't...
Johan
--
--
johan.wikman@ntc.nokia.com; C=FI,A=Elisa,P=Nokia Telecom,S=Wikman,Gi=Johan
TL4E - P.P. Box 12, SF-02611 Espoo 61, Finland
Author: wikman@king.trs.ntc.nokia.com (Johan Wikman)
Date: 22 Mar 1995 10:47:12 GMT Raw View
>>>>> "Ed" == Ed Osinski <osinski@merv.cs.nyu.edu> writes:
Ed> It's too bad that constructors can't be const. There have been a number of
Ed> times that I've wanted const objects to be constructed with different
Ed> parameters than non-const objects; for example:
Ed> class C;
Ed> class D {
Ed> public:
Ed> D (C *);
Ed> const D (const C *);
Ed> ...
Ed> };
Ed> Alas, the language doesn't have this feature. Has this ever been
Ed> considered? (In case the syntax above wasn't self-explanatory :-),
Ed> the word "const" preceding a constructor name would mean that it
Ed> was only applicable to construction of const objects.) I feel
Ed> that, while const as it stands today is quite useful, missing this
Ed> and a couple of other features are preventing more powerful use of it.
I agree completely. I have wanted const constructors - that would
behave exactly as you describe - for quite some time. I posted an
article about them here on comp.std.c++ but (to my surprice) there was
no reaction at all.
Johan
--
--
johan.wikman@ntc.nokia.com; C=FI,A=Elisa,P=Nokia Telecom,S=Wikman,Gi=Johan
TL4E - P.P. Box 12, SF-02611 Espoo 61, Finland
Author: pete@borland.com (Pete Becker)
Date: 22 Mar 1995 23:48:05 GMT Raw View
In article <WIKMAN.95Mar22124712@king.trs.ntc.nokia.com>, wikman@king.trs.ntc.nokia.com (Johan Wikman) says:
>
>
>>>>>> "Ed" == Ed Osinski <osinski@merv.cs.nyu.edu> writes:
>
>Ed> It's too bad that constructors can't be const. There have been a number of
>Ed> times that I've wanted const objects to be constructed with different
>Ed> parameters than non-const objects; for example:
>
>Ed> class C;
>
>Ed> class D {
>Ed> public:
>Ed> D (C *);
>Ed> const D (const C *);
>Ed> ...
>Ed> };
>
>Ed> Alas, the language doesn't have this feature. Has this ever been
>Ed> considered? (In case the syntax above wasn't self-explanatory :-),
>Ed> the word "const" preceding a constructor name would mean that it
>Ed> was only applicable to construction of const objects.) I feel
>Ed> that, while const as it stands today is quite useful, missing this
>Ed> and a couple of other features are preventing more powerful use of it.
>
>I agree completely. I have wanted const constructors - that would
>behave exactly as you describe - for quite some time. I posted an
>article about them here on comp.std.c++ but (to my surprice) there was
>no reaction at all.
>
Can someone post an example of some meaningful code that would be
written significantly differently in the presence of such a new rule? Or
is this simply a case of orthogonality for its own sake?
-- Pete
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Sat, 18 Mar 1995 04:36:23 GMT Raw View
In article <3kbivk$k9k@hustle.rahul.net>,
Ronald F. Guilmette <rfg@rahul.net> wrote:
>In article <cppD5Cw13.AII@netcom.com>, Robin Rowe <cpp@netcom.com> wrote:
>>
>I should know better than to do this here in comp.std.c++, but I'll stick
>my neck out and try a wild-ass guess.
>
>My guess is that we can say (and should say) that your `b' object only
>_becomes_ constant _after_ it has been constructed.
Pretty good guess. More precisely, the non-mutable
memory of the object denoted by a variable declared const _may_
be write protected after the constructor body is run, and this
rule has been extended to new expressions.
The write protection has to be turned off before the
destructor is run.
The point is that if you write to such an object all bets
are off.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA Phone: 61-2-566-2189
Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 20 Mar 1995 10:07:01 GMT Raw View
In article <cppD5GpEL.8C@netcom.com>, cpp@netcom.com (Robin Rowe) writes:
[..]
|> What harm would befall a const object if its ctor
|> called a const method in preference to the non-const one? Is this
|> something that was thought out, or is it just that way because it's that
|> way?
The harm is the introduction of ambiguities in the static typecheck
of the ctor (or else the introduction of a leathal hole in the typecheck
- but maybe you prefere dynamiuc typing? ).
Consider:
class String {
float foo (T1&t) {}
String& foo (T2&t) {}
public:
T1 Say() { return ...; }
T2 Say() const { return .. ; }
String()
{
T1 t1 = Say();
T2 t1 = Say();
float f = foo( Say() );
String s = foo( Say() );
}
};
Now the compiler could't tell what type Say() has within the ctor.
( Is t1=Say() or t2=Say() correct ? What foo is called? ...)
A workable solution for different ctor-behavior is to define
special ctors for const objects, like proposed by Ed Osinski:
EO> class C;
EO>
EO> class D {
EO> public:
EO> D (C *);
EO> const D (const C *);
EO> ...
EO> };
Ulf Schuenemann
--------------------------------------------------------------------
Ulf Sch nemann
Institut f r Informatik, Technische Universit t M nchen.
email: schuenem@informatik.tu-muenchen.de
Author: osinski@merv.cs.nyu.edu (Ed Osinski)
Date: 17 Mar 1995 01:57:17 GMT Raw View
In article <cppD5GpEL.8C@netcom.com>, cpp@netcom.com (Robin Rowe) writes:
|> In article <JASON.95Mar13003630@phydeaux.cygnus.com>,
|> Jason Merrill <jason@cygnus.com> wrote:
|> >>>>>> Robin Rowe <cpp@netcom.com> writes:
|> >Because during construction the object is not const.
|>
|> I don't quite follow. What harm would befall a const object if its ctor
|> called a const method in preference to the non-const one? Is this
|> something that was thought out, or is it just that way because it's that
|> way?
|>
|> The reason I ask is it occurs to me that a const object might want to be
|> constructed differently from a non-const one. Since a constructor can't
^^^^^^^^^^^^^^^^^^^
|> be const, and the ctor won't call the const method over the non-const one
^^^^^^^^
It's too bad that constructors can't be const. There have been a number of
times that I've wanted const objects to be constructed with different
parameters than non-const objects; for example:
class C;
class D {
public:
D (C *);
const D (const C *);
...
};
Alas, the language doesn't have this feature. Has this ever been considered?
(In case the syntax above wasn't self-explanatory :-), the word "const"
preceding a constructor name would mean that it was only applicable to
construction of const objects.) I feel that, while const as it stands today
is quite useful, missing this and a couple of other features are preventing
more powerful use of it.
|> (as common sense could reasonably expect), there seems no way to accomplish
|> this. I'd like to know what I'm being protected from doing. What would go
|> wrong if I could do this?
|>
|> Thanks.
|>
|> Robin
|> --
|> -----
|> Robin Rowe cpp@netcom.com 408-626-6646 Carmel, CA
|> Rowe Technology C++ Design/Training Email for sample C++ Newsletter!
--
---------------------------------------------------------------------
Ed Osinski
Computer Science Department, New York University
E-mail: osinski@cs.nyu.edu
---------------------------------------------------------------------
In the early years of the 16th century, to combat the rising tide of
religious unorthodoxy, the Pope gave Cardinal Ximinez of Spain leave
to move without let or hindrance throughout the land, in a reign of
violence, terror and torture that makes a smashing film. This was
the Spanish Inquisition...
-- Monty Python's Flying Circus
Author: "Ronald F. Guilmette" <rfg@rahul.net>
Date: 17 Mar 1995 08:58:27 GMT Raw View
In article <cppD5Cw13.AII@netcom.com>, Robin Rowe <cpp@netcom.com> wrote:
>
>Would someone be so kind as to explain why a constructor of a const object
>prefers a non-const method?
>
>#include <iostream.h>
>
>class String
>{public:
> void Say()
> { cout<<"non-const\n";
> }
> void Say() const
> { cout<<"const\n";
> }
> String()
> { Say();
>} };
>
>int main()
>{ String a; //non-const
> a.Say(); //non-const
> const String b; //non-const (Why?)
> b.Say(); //const
> return 0;
>}
I should know better than to do this here in comp.std.c++, but I'll stick
my neck out and try a wild-ass guess.
My guess is that we can say (and should say) that your `b' object only
_becomes_ constant _after_ it has been constructed.
--
-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- E-mail: rfg@segfault.us.com ----------- Purveyors of Compiler Test ----
-------------------------------------------- Suites and Bullet-Proof Shoes -
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Fri, 17 Mar 1995 17:53:06 GMT Raw View
In article <JASON.95Mar14224655@phydeaux.cygnus.com>,
Jason Merrill <jason@cygnus.com> wrote:
>>>>>> Robin Rowe <cpp@netcom.com> writes:
>
>> I don't quite follow. What harm would befall a const object if its ctor
>> called a const method in preference to the non-const
>
>None, probably,
The _point_ of having a body in a
constructor is to _write_ to parts of the object to initialise it.
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA Phone: 61-2-566-2189
Author: cpp@netcom.com (Robin Rowe)
Date: Wed, 15 Mar 1995 03:23:08 GMT Raw View
In article <JASON.95Mar13003630@phydeaux.cygnus.com>,
Jason Merrill <jason@cygnus.com> wrote:
>>>>>> Robin Rowe <cpp@netcom.com> writes:
>Because during construction the object is not const.
I don't quite follow. What harm would befall a const object if its ctor
called a const method in preference to the non-const one? Is this
something that was thought out, or is it just that way because it's that
way?
The reason I ask is it occurs to me that a const object might want to be
constructed differently from a non-const one. Since a constructor can't
be const, and the ctor won't call the const method over the non-const one
(as common sense could reasonably expect), there seems no way to accomplish
this. I'd like to know what I'm being protected from doing. What would go
wrong if I could do this?
Thanks.
Robin
--
-----
Robin Rowe cpp@netcom.com 408-626-6646 Carmel, CA
Rowe Technology C++ Design/Training Email for sample C++ Newsletter!
Author: jason@cygnus.com (Jason Merrill)
Date: 15 Mar 1995 06:46:55 GMT Raw View
>>>>> Robin Rowe <cpp@netcom.com> writes:
> I don't quite follow. What harm would befall a const object if its ctor
> called a const method in preference to the non-const
None, probably, but it would involve adding Yet Another special case to the
language, which is already (IMO) swimming in ill-conceived special cases
which merely point out the inadequacy of the rules they modify. Some of
these are necessitated by the C heritage, and most of the rest are due to
the necessity of remaining compatible with the large body of existing C++
code, but that doesn't make them any more aesthetically appealing.
In a constructor, 'this' has type T*.
is simpler than
In a constructor, 'this' has type T*, except that calling methods from the
constructor will tend to prefer const methods if the object being
constructed is const.
The latter rule would also involve implementation headaches.
Jason
Author: cpp@netcom.com (Robin Rowe)
Date: Mon, 13 Mar 1995 01:55:50 GMT Raw View
Would someone be so kind as to explain why a constructor of a const object
prefers a non-const method?
#include <iostream.h>
class String
{public:
void Say()
{ cout<<"non-const\n";
}
void Say() const
{ cout<<"const\n";
}
String()
{ Say();
} };
int main()
{ String a; //non-const
a.Say(); //non-const
const String b; //non-const (Why?)
b.Say(); //const
return 0;
}
Thanks.
Robin
--
-----
Robin Rowe cpp@netcom.com 408-626-6646 Carmel, CA
Rowe Technology C++ Design/Training Email for sample C++ Newsletter!
Author: jason@cygnus.com (Jason Merrill)
Date: 13 Mar 1995 08:36:30 GMT Raw View
>>>>> Robin Rowe <cpp@netcom.com> writes:
> Would someone be so kind as to explain why a constructor of a const object
> prefers a non-const method?
Because during construction the object is not const.
Jason
Author: herbs@interlog.com (Herb Sutter)
Date: Mon, 13 Mar 95 14:36:04 GMT Raw View
In article <cppD5Cw13.AII@netcom.com>, cpp@netcom.com (Robin Rowe) wrote:
>
>Would someone be so kind as to explain why a constructor of a const object
>prefers a non-const method?
It's the difference between initialisation and assignment: A const object
can (must!) be initialized, but it can't be assigned to. The only time it
can be given a value is in its declaration -- which, for an object, means in
its ctor. Const-ness begins when the ctor is finished.
Put another way, to the ctor all the class' objects are mutable, else it
wouldn't be able to write to them! :-)
>#include <iostream.h>
>
>class String
>{public:
> void Say()
> { cout<<"non-const\n";
> }
> void Say() const
> { cout<<"const\n";
> }
> String()
> { Say();
>} };
>
>int main()
>{ String a; //non-const
> a.Say(); //non-const
> const String b; //non-const (Why?)
> b.Say(); //const
> return 0;
>}
>
>Thanks.
>
>Robin
>
>
---
Herb Sutter #include <std_disclaimer.h>
herbs@interlog.com "Me? Paranoid? ... Uh, why do you ask?"
Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Tue, 14 Mar 1995 03:09:57 GMT Raw View
In article <3k1ljq$70e@steel.interlog.com>,
Herb Sutter <herbs@interlog.com> wrote:
>In article <cppD5Cw13.AII@netcom.com>, cpp@netcom.com (Robin Rowe) wrote:
>>
>>Would someone be so kind as to explain why a constructor of a const object
>>prefers a non-const method?
>
>It's the difference between initialisation and assignment: A const object
>can (must!) be initialized, but it can't be assigned to. The only time it
>can be given a value is in its declaration -- which, for an object, means in
>its ctor. Const-ness begins when the ctor is finished.
>
>Put another way, to the ctor all the class' objects are mutable, else it
>wouldn't be able to write to them! :-)
More correctly, at the very start of execution of the constructor,
the "this" pointer has dynamic type "void*". The environment ensures
that the address is properly aligned and sufficient storage available,
but the memory is just raw bits.
At the end of constructor execution, the this pointer
has dynamic type T*. (For class T). Then, the environment
can write protect the non-mutable storage of the object, if it is
declared "const".
--
JOHN (MAX) SKALLER, INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA Phone: 61-2-566-2189