Topic: What const is/was for
Author: Jonathan de Boyne Pollard <J.deBoynePollard@tesco.net>
Date: 1999/10/06 Raw View
Andrei Alexandrescu wrote:
> I'd be happy to see a compelling example in favor of the
> Standard rule.
The problem with answering that challenge is that what you are asking for is
difficult to provide. This is because the Standard C++ semantics are more
permissive than the ARM semantics. If Standard C++ were *stricter* than the
ARM, in order to prevent something that had been discovered to be undesirable,
then one could easily come up with an example where one could say "See this
here, that is legal in ARM C++? Well it's a daft thing to do and we've thus
made it illegal in Standard C++.".
But the converse is in fact the case here. The ARM semantics were aimed at
preventing one from doing something daft, but it turns out that they actually
*didn't do so*, so there wasn't a justification for keeping them in Standard
C++. ARM C++ attempted to solve a particular problem by giving a certain
meaning to `const', but that didn't actually solve that problem. The
underlying problem is not one of constancy, but one of lifetime and storage
class. The "const contract" cannot be extended to be a "non-deletability
contract" as well, simply because one can have const objects with heap storage
class (which shouldn't be "non-deleteable") and non-const objects with static
or auto storage class (which should be).
So it's not that ARM C++ had a mechanism for a "non-deletability contract"
that has been taken away. It's that ARM C++ had a mechanism for a "const
contract" that was thought to cover non-deletability as well, but actually
didn't because it couldn't.
The question *now* becomes "Obviously a non-deletability contract is a
desirable feature. So how can we provide one ?".
M. Bonnard and Mr Glassborow have both suggested a solution to the actual
problem of providing a "non-deletability contract" mechanism, which is to
introduce a new cv qualifier `no_delete'. ('no_destroy' probably provides too
strict a qualification for what is needed, by the way, since it not only
affects `delete' expressions but also affects explicit destructor call, which,
again, is _not_ what is actually desired.)
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Jens Kilian <Jens_Kilian@bbn.hp.com>
Date: 1999/09/30 Raw View
Jeff Rife <wevsr@nabs.net> writes:
> Huh? This doesn't follow. How can "we" create that object? If the
> destructor is not accessible, according to 12.4/10:
>
> "A program s ill formed if an object of class type or array thereof is
> declared and the destructor for the class is not accessible at the point
> of the declaration."
"An object is declared" doesn't apply to creation via "new":
class MineAllMine
{
public:
MineAllMine(void);
void suicide(void)
{
delete this;
}
private:
~MineAllMine(void);
};
void foo(void)
{
// MineAllMine illegal; // if uncommented, program becomes ill formed
MineAllMine *legal = new MineAllMine; // this is OK!
legal->suicide(); // and so is this
}
This is actually a valuable programming technique.
Regards,
Jens.
--
mailto:jjk@acm.org phone:+49-7031-14-7698 (HP TELNET 778-7698)
http://www.bawue.de/~jjk/ fax:+49-7031-14-7351
PGP: 06 04 1C 35 7B DC 1F 26 As the air to a bird, or the sea to a fish,
0x555DA8B5 BB A2 F0 66 77 75 E1 08 so is contempt to the contemptible. [Blake]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: ncm@nospam.cantrip.org (Nathan Myers)
Date: 1999/09/28 Raw View
Zalman Stern <zalman@netcom13.netcom.com> wrote:
>
>If unconst were needed commonly, it could be added to the standard and
>explained that it takes a pointer and returns the non-const version
>thereof.
That unconst was always possible, but doesn't seem to have been needed
much, argues that templates to be instantiated on "const T" may not
have as much utility as is being ascribed to them.
--
Nathan Myers
ncm@nospam.cantrip.org http://www.cantrip.org/
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/09/28 Raw View
Zalman Stern wrote:
>
> Andrew Koenig <ark@research.att.com> wrote:
> : Your unconst function is far from trivial. It is, for example,
> : much harder to explain than the difference between assignment
> : and initialization.
>
> Some people have a hard time with the idea that templates pattern match on
> types and can therfore be used for type rewriting as is taken for granted
> in most functional languages. Other people intutively pick it up almost
> immediately. (From my sample of about ten programmers I've worked with who
> I've explained templates to.)
>
> If unconst were needed commonly, it could be added to the standard and
> explined that it takes a pointer and returns the non-const version
> thereof. Programmers wouldn't have to understand its inner workings to use
> the function. However one probably does not want such a convienient
> typesafe way to remove const and if a language feature makes it common to
> need such a feature, then perhaps that feature is actually weakening const
> rather than strengthening it.
If the only use is to provide templates with deletable pointers,
I'd prefer a traits-style template like that someone has
posted in this thread. Maybe extended like this:
template<class T> struct cv_traits;
{
typedef T no_const;
typedef T no_volatile;
typedef T no_cv;
};
template<class T> struct cv_traits<T const>
{
typedef T no_const;
typedef T const no_volatile;
typedef T no_cv;
};
template<class T> struct cv_traits<T volatile>
{
typedef T volatile no_const;
typedef T no_volatile;
typedef T no_cv;
};
template<class T> struct cv_traits<T const volatile>
{
typedef T volatile no_const;
typedef T const no_volatile;
typedef T no_cv;
};
Now the template could be written with full protection
against passed-in qualifiers:
template<class T> void foo()
{
typedef typename ptr_traits<T>::no_cv T_base;
T_base* p = new T_base;
// ...
delete p;
}
foo<const int>(); // OK, even with ARM rule
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: scorp@btinternet.com (Dave Harris)
Date: 1999/09/29 Raw View
wevsr@nabs.net (Jeff Rife) wrote:
> Huh? This doesn't follow. How can "we" create that object? If the
> destructor is not accessible, according to 12.4/10:
>
> "A program s ill formed if an object of class type or array thereof is
> declared and the destructor for the class is not accessible at the
> point of the declaration."
Ah. I don't have a copy of the standard (and the web site refused to give
me one) and didn't know about that section. And it is vastly surprising to
me. Are you sure you're not mis-interpreting it? Here's why I ask.
The kind of class I have in mind is designed to be used with a generic
counted pointer:
class RefCount {
public:
RefCount() : m_count(0) {
}
void addRef() { // For use by SmartPtr<>.
++m_count;
}
void release() { // For use by SmartPtr<>.
if (--m_count == 0)
delete this;
}
//...
protected:
virtual ~RefCount() = 0;
};
Subclasses follow a similar pattern of public constructor and protected
destructor. We make the constructor public so that anyone can create
instances. We don't use a factory because of the complications of passing
constructor arguments, but we can use a generic smart pointer because
destructors don't take arguments.
The destructor is protected so that the only way to delete objects is
through the release() method. Thus:
RefCountSubclass a; // Compile error.
SmartPtr<RefCountSubclass> b( new RefCountSubclass ); // OK!
It becomes much harder to misuse the class because casual attempts to
delete it are forbidden. You can't create the object on the stack, in an
array or aggregated into some larger object where it would be deleted
implicitly. You can't use the usual delete expression. The correct way is
the only way. It is a very safe idiom.
And now you tell me this leads to ill-formed code. Are you sure? Can you
explain why the standard would wish to forbid classes like this?
(Incidently, code like the above compiles happily with my local system.)
Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
brangdon@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/09/29 Raw View
scorp@btinternet.com (Dave Harris) writes:
> wevsr@nabs.net (Jeff Rife) wrote:
> > "A program s ill formed if an object of class type or array thereof is
> > declared and the destructor for the class is not accessible at the=20
> > point of the declaration."
> Ah. I don't have a copy of the standard (and the web site refused to give=20
> me one) and didn't know about that section. And it is vastly surprising to=20
> me. Are you sure you're not mis-interpreting it? Here's why I ask.
> ...
> It becomes much harder to misuse the class because casual attempts to=20
> delete it are forbidden. You can't create the object on the stack, in an=20
> array or aggregated into some larger object where it would be deleted=20
> implicitly. You can't use the usual delete expression. The correct way is=20
> the only way. It is a very safe idiom.
You are agreeing with each other.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Zalman Stern <zalman@netcom13.netcom.com>
Date: 1999/09/27 Raw View
Andrew Koenig <ark@research.att.com> wrote:
: Your unconst function is far from trivial. It is, for example,
: much harder to explain than the difference between assignment
: and initialization.
Some people have a hard time with the idea that templates pattern match on
types and can therfore be used for type rewriting as is taken for granted
in most functional languages. Other people intutively pick it up almost
immediately. (From my sample of about ten programmers I've worked with who
I've explained templates to.)
If unconst were needed commonly, it could be added to the standard and
explined that it takes a pointer and returns the non-const version
thereof. Programmers wouldn't have to understand its inner workings to use
the function. However one probably does not want such a convienient
typesafe way to remove const and if a language feature makes it common to
need such a feature, then perhaps that feature is actually weakening const
rather than strengthening it.
If one were not allowed to delete const poitners, I'd want auto_ptr to
still work with const pointers. I'd also want some conventions for deleting
members that are const pointers in a destructor without using brute force
casts. The casts ruin all sorts of formal reasoning mechanisms about a body
of code.
-Z-
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: scorp@btinternet.com (Dave Harris)
Date: 1999/09/27 Raw View
zalman@netcom13.netcom.com (Zalman Stern) wrote:
> If one were not allowed to delete const poitners, I'd want auto_ptr to
> still work with const pointers.
I think what you really want is a different smart pointer, perhaps called
auto_ptr_const, which takes a non-const argument and exposes it as const
and does the delete behind the scenes. Candidate classes have been posted
in this newsgroup before. They don't need casts.
> I'd also want some conventions for deleting members that are
> const pointers in a destructor without using brute force casts.
Why won't auto_ptr_const<> do the job? I think you have a good point, and
code like:
class S {
const T *t;
public:
S() : t( new T ) {}
~S() : { delete t; }
};
may be more common than the const collections. However, even today such
code should probably use auto_ptr, for reasons of exception safety. Where
templates are not involved, switching smart pointer classes is trivial.
Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
brangdon@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Jeff Rife <wevsr@nabs.net>
Date: 1999/09/27 Raw View
Dave Harris (scorp@btinternet.com) wrote:
> As far as I can tell, people want to make a special exemption for delete
> because of some general rule that "if you create it you can delete it".
> But there is no such rule. Consider:
>
> class Test2 {
> public:
> Test2();
> protected:
> ~Test2();
> };
>
> Clearly we cannot instantiate f<Test2>() whatever the rule for const
> delete. Sometimes we can create objects we can't delete, and when that
> happens we can't use those objects with templates which require delete.
Huh? This doesn't follow. How can "we" create that object? If the
destructor is not accessible, according to 12.4/10:
"A program s ill formed if an object of class type or array thereof is
declared and the destructor for the class is not accessible at the point
of the declaration."
Now, it can be created using the factory method, etc., but then the
definition of "we" has to change. And, just because there is a factory
to create and no "garbage dump" to destroy an object doesn't mean there
*couldn't* be a "garbage dump".
Since I can't see other places in the standard where "we can create objects
we can't delete", then we should be able to delete const objects, to
keep everything parallel.
--
Jeff Rife | "Well, it's a dog-eat-dog world, Sammy, and
19445 Saint Johnsbury Lane | I'm wearing Milk-Bone underwear."
Germantown, MD 20876-1610 |
Home: 301-916-8131 | -- Norm Peterson
Work: 301-770-5800 Ext 5335 |
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]