Topic: C++0x Wish List (explicit class)
Author: steve@steveheller.com (Steve Heller)
Date: Tue, 3 Sep 2002 17:49:13 +0000 (UTC) Raw View
kanze@gabi-soft.de (James Kanze) wrote:
>Allan_W@my-dejanews.com (Allan W) wrote in message
>news:<23b84d65.0208081146.169d3d83@posting.google.com>...
>> rmaddox@isicns.com (Randy Maddox) wrote
>> > The other issue is that with either the newly proposed use of
>> > explicit or with the private declaration and no definition idiom you
>> > can partially change your mind, i.e., add any one of the prohibited
>> > operations without affecting the remaining prohibitions. With
>> > boost::noncopyable it's all or nothing.
>
>> Note that you can implement copy constructor in terms of assignment:
>> T::T(const T&t) { (*this)=t; }
>> Also, while it's not a good idea to implement assignment in terms of
>> copy constructor, it is at least possible.
>
>> Can you think of an example where you'd want to define one of these
>> functions but not the others? I can't.
>
>Yes. Polymorphism and assignment doesn't work well together,
Unless you use "safe polymorphism", which hides the pointer in a
"manager" object which can be assigned with normal syntax.
>but it is
>not unusual to want to be able to clone a polymorphic object. In such
>cases, I'll declare both the copy constructor and the assignment
>operator private; I'll define the copy constructor, but not the
>assignment operator.
--
Steve Heller
http://www.steveheller.com
Author of "C++: A Dialog", "Optimizing C++", and other books
Free online versions of "Who's Afraid of C++?" and "Optimizing C++" are now available
at http://www.steveheller.com/whos and http://www.steveheller.com/opt
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: ahp6@email.byu.edu (Adam Peterson)
Date: Tue, 3 Sep 2002 20:38:58 +0000 (UTC) Raw View
> I also like this proposal.
>
> How about explicit classes also making all constructors explicit unless they
> are marked "implicit"?
>
> Mike
I'm in favor of this part of it, except that I almost always want the
compiler generated copy ctor/assignment operator. (80% of the time
that I don't, it's already suppressed incidentally by inheritance or
aggregation.) If I could mark a class explicit to suppress conversion
operators I don't specify, but somehow still get the compiler
ctor/asmts, I'd use explicit on every class.
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: sa_schreuder@wanadoo.nl (Sjoerd Schreuder)
Date: Wed, 4 Sep 2002 23:37:54 +0000 (UTC) Raw View
Adam Peterson wrote:
> If I could mark a class explicit to suppress conversion
> operators I don't specify, but somehow still get the compiler
> ctor/asmts, I'd use explicit on every class.
I get tired writing the 'standard' implementations for member functions
all the time. swap(), strong exception safe operator=(), operator+()
in terms of operator+=(). It's all in the books and could (should) be
generated automatically.
So here is my draft of a draft of a proposal.
Let's reuse the keyword 'default'! After a member declaration, 'default'
forces a compiler to generate the standard definition. This doesn't break
any code, as default is already a keyword and it will be introduced
at a place in the grammar it is not allowed at this moment.
As soon as 'standard' implementations for certain functions are established,
they could be added to the list of default-able functions.
explicit class Foo
{
private:
int a;
public:
Foo() : a(42) {} // do not want the default here
Foo(const Foo &) default;
const Foo &operator = (const Foo &) default;
void swap(Foo &) default; // I wish....
};
Sjoerd Schreuder
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Michael Glassford" <nospam@hotmail.com>
Date: Wed, 28 Aug 2002 13:00:59 CST Raw View
I also like this proposal.
How about explicit classes also making all constructors explicit unless they
are marked "implicit"?
Mike
"Francis Glassborow" <francis.glassborow@ntlworld.com> wrote in message
news:vhGu8zAcrVZ9EwzA@robinton.demon.co.uk...
> In article <ak3eve$4n1$1@acs2.byu.edu>, Adam H. Peterson
> <ahp6@email.byu.edu> writes
> >Well, I personally didn't learn about the keyword "explicit" until I had
> >been programming for years, and then not from a language class, but from
> >reading documentation about C++. If you think explaining explicit class
in
> >terms of the other use of explicit, you'll have to explain the other use
of
> >explicit, along with all the strange rules involving compiler conversions
> >(such as ambiguity and the one-conversion rule). Personally, I would
rather
> >have seen all constructors explicit unless marked "implicit", but we have
to
> >work with what we have now. Anyway, see below for the continuation of
this
> >point.
>
> It was a relatively late introduction to the language and was introduced
> exactly because many of us got very tired of having to teach one of
> several horrible hacks in order to provide non-converting constructors.
> Of course many authors and lecturers take for ever to catch up even
> after compiler implementors have done so.
>
> Of course it should have been the other way round (single argument ctors
> should not have been conversion operators by default) but it was way too
> late to do that by the time we woke up to just how rotten the techniques
> we had were. Note that the proposed new use for explicit is again to
> prevent having to use hacks to turn off a feature when we do not want
> it. If compiler implementors tell me that this proposal would cause
> problems in parsing etc. I will listen, but if it does not, and as it
> will not break a line of existing code I would strongly favour going
> ahead.
>
> --
> Francis Glassborow ACCU
> 64 Southfield Rd
> Oxford OX4 1PA +44(0)1865 246490
> All opinions are mine and do not represent those of any organisation
>
> ---
> [ 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://www.jamesd.demon.co.uk/csc/faq.html ]
>
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Adam H. Peterson" <ahp6@email.byu.edu>
Date: Thu, 22 Aug 2002 20:01:20 GMT Raw View
> On the one hand we can explain to new C++ developers that explicit,
> which has already been demonstrated to indicate to the compiler the
> developer's intent that a ctor not be implicitly used for conversions,
> can also be used to tell the compiler to not implicitly generate the
> default and copy ctor, assignment operator and dtor that it otherwise
> would. This seems to me a consistent use of the keyword explicit and
> directly understandable.
Well, I personally didn't learn about the keyword "explicit" until I had
been programming for years, and then not from a language class, but from
reading documentation about C++. If you think explaining explicit class in
terms of the other use of explicit, you'll have to explain the other use of
explicit, along with all the strange rules involving compiler conversions
(such as ambiguity and the one-conversion rule). Personally, I would rather
have seen all constructors explicit unless marked "implicit", but we have to
work with what we have now. Anyway, see below for the continuation of this
point.
>
> On the other hand we can explain to new C++ developers that private
> derivation from a misnamed class will accomplish the same goal, but
> they have to be careful to use private inheritance and not public. We
> also have to explain that although private inheritance is often
> explained as "implementation inheritance" we are not inheriting any
> implementation in this case. We also have to explain that while a
> base class is usually recognized by its virtual dtor, and possibly
> other virtual members or a protected interface, that the
> boost::noncopyable base class violates the virtual dtor rule because
> it's not really a base class in the usual sense, but merely a
> workaround, and one that they should not emulate in their own base
> classes. Oh, yes, and let us not forget that this workaround also
> introduces an unneeded external dependency.
The rule is that a base class that is used for inheritance of interface
needs to have a virtual destructor. A base class used for inheritance of
implementation needn't (and in my code, often doesn't). (The rule is
actually even tighter. A virtual destructor is only needed in a base class
through which a polymorphic delete may be performed. This doesn't happen in
inheritance of implementation, and it might not be a bad thing for a learner
to spot this once they've figured out that noncopyable _is_ a base class in
the first place.)
But my point is that neither of these methods has to actually be explained
in full to the learner of C++. You just tell them how to do it (i.e. by
writing ": noncopyable" or by writing "explict class" or whatever you decide
to end up using) and they will take it at face value. They won't realize
they're using private inheritance, and they aren't liable to accidentally
use public inheritance. It is only later when they're on their way to
mastering the language that they'll realize how it works.
And again, I don't see how a dependency on the standard library is so
devastating. I have yet to write a single translation unit that didn't have
such an "external dependency".
>
> I'm sorry, but I just cannot accept this as a convincing argument. In
> fact, re-reading Mr. Peterson's explanation sounds to me like a good
> argument AGAINST use of boost::noncopyable. I stand my my earlier
> assertion that the new use of explicit is clearer and cleaner than use
> of boost::noncopyable, and that the committee ought to take a look at
> this suggestion.
I will grant you the right to your opinion, and I am fairly convinced that
we will not see eye to eye on this.
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Thu, 22 Aug 2002 23:43:48 GMT Raw View
In article <ak3eve$4n1$1@acs2.byu.edu>, Adam H. Peterson
<ahp6@email.byu.edu> writes
>Well, I personally didn't learn about the keyword "explicit" until I had
>been programming for years, and then not from a language class, but from
>reading documentation about C++. If you think explaining explicit class in
>terms of the other use of explicit, you'll have to explain the other use of
>explicit, along with all the strange rules involving compiler conversions
>(such as ambiguity and the one-conversion rule). Personally, I would rather
>have seen all constructors explicit unless marked "implicit", but we have to
>work with what we have now. Anyway, see below for the continuation of this
>point.
It was a relatively late introduction to the language and was introduced
exactly because many of us got very tired of having to teach one of
several horrible hacks in order to provide non-converting constructors.
Of course many authors and lecturers take for ever to catch up even
after compiler implementors have done so.
Of course it should have been the other way round (single argument ctors
should not have been conversion operators by default) but it was way too
late to do that by the time we woke up to just how rotten the techniques
we had were. Note that the proposed new use for explicit is again to
prevent having to use hacks to turn off a feature when we do not want
it. If compiler implementors tell me that this proposal would cause
problems in parsing etc. I will listen, but if it does not, and as it
will not break a line of existing code I would strongly favour going
ahead.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: rmaddox@isicns.com (Randy Maddox)
Date: Thu, 22 Aug 2002 15:50:53 GMT Raw View
Let me see if I have this straight.
First, explicit is already a keyword, so adding a new use for it does
not add a new keyword. Second, the existing use of explicit is in
application to a ctor and its meaning is to tell the compiler to NOT
use that ctor for implicit conversions. Finally, the proposed new use
of explicit is to tell the compiler to NOT implicitly generate a
default or copy ctor, assignment operator, or dtor for a class, while
still allowing the user to provide such members as desired.
Now, it is pretty common for the designer of a class to want full
control over how, and whether, an object of that class may be
constructed, copied and destroyed. And it is common enough to not
want the compiler-supplied defaults that there are currently two
idioms in widespread use to prevent this: the private declaration
with no definition idiom, and derivation from the misnamed
boost::noncopyable.
Mr. Peterson agrees that the situation does commonly arise and is an
issue that needs to be addressed in the Standard, but insists that the
best approach is to bring boost::noncopyable into the Standard as
std::noncopyable and let that be the Standard-supported idiom. He
argues below that explaining this idiom to new C++ developers is a
good thing because it provides an example of private inheritance in
action.
I will readily grant Mr. Peterson's point that it may be more likely
that boost::noncopyable will be brought into the Standard than it is
that the new use of explicit will be standardized, but I must
respectfully disagree with the rest of his argument.
On the one hand we can explain to new C++ developers that explicit,
which has already been demonstrated to indicate to the compiler the
developer's intent that a ctor not be implicitly used for conversions,
can also be used to tell the compiler to not implicitly generate the
default and copy ctor, assignment operator and dtor that it otherwise
would. This seems to me a consistent use of the keyword explicit and
directly understandable.
On the other hand we can explain to new C++ developers that private
derivation from a misnamed class will accomplish the same goal, but
they have to be careful to use private inheritance and not public. We
also have to explain that although private inheritance is often
explained as "implementation inheritance" we are not inheriting any
implementation in this case. We also have to explain that while a
base class is usually recognized by its virtual dtor, and possibly
other virtual members or a protected interface, that the
boost::noncopyable base class violates the virtual dtor rule because
it's not really a base class in the usual sense, but merely a
workaround, and one that they should not emulate in their own base
classes. Oh, yes, and let us not forget that this workaround also
introduces an unneeded external dependency.
I'm sorry, but I just cannot accept this as a convincing argument. In
fact, re-reading Mr. Peterson's explanation sounds to me like a good
argument AGAINST use of boost::noncopyable. I stand my my earlier
assertion that the new use of explicit is clearer and cleaner than use
of boost::noncopyable, and that the committee ought to take a look at
this suggestion.
Randy.
"Adam H. Peterson" <ahp6@email.byu.edu> wrote in message news:<ajjk97$3pb$1@acs2.byu.edu>...
> Okay, here it is again. (I'm talking here about making boost::noncopyable
> part of the standard library vs. changing the language to add explicit
> class.)
>
> 1) We already know it works, and how it works, as we have a proof of concept
> in boost. Furthermore, the things in boost's library are already on a track
> towards standardization and have a better chance of actually making it into
> the next version of the language.
> 2) It can in most cases be implemented by changing the standard library
> alone, so we don't have to make sure we haven't broken the compiler after
> changing the grammar since we probably don't need to change the compiler.
> 3) It doesn't involve overloading a keyword, introducing possible confusion
> to a newcomer to the language.
> 4) It introduces one of the uses of private inheritance, so newcomers to the
> language observing this may learn how to use it more effectively. (Note
> that it doesn't have to be explained this way. But an astute learner may
> simply observe this.)
> 5) It doesn't introduce yet another way to do something that programmers are
> already doing a different way, making skills more portable from one coding
> style to another, and preventing the invariable holy wars about how to
> suppress these automatic members.
>
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: rmaddox@isicns.com (Randy Maddox)
Date: Mon, 12 Aug 2002 16:44:20 GMT Raw View
"Adam H. Peterson" <ahp6@email.byu.edu> wrote in message news:<aiphem$9e5$1@acs2.byu.edu>...
> Here's my argument against:
>
> I don't see how explicit is at all different from private inheritance from
> boost::noncopyable. Either suppresses automatic copy constructor and
> assignment constructor generation, and either can be explicitly overridden.
> The only difference I can see is that explicit also suppresses the automatic
> generation of a default constructor. I see this as a non-issue, since that
> will be suppressed if you declare any constructor yourself anyways. And if
> you don't declare any constructor, why would you want to suppress default
> constructor generation? The (extremely few, and almost academic) cases I
> can think of where this would be desirable are easily handled by private
> constructor declaration.
>
> So, really, what does explicit class buy us anyway? In my view, nothing,
> and certainly not enough to modify the language.
>
We all seem to be in agreement that boost::noncopyable and the
proposed new use of explicit solve the exact same problem, i.e., they
prevent the compiler from automatically generating unwanted members
for a class, and both allow the developer to later provide those
members if and as they become desirable. So far, so good.
However, I would argue that the proposed new use of explicit is
cleaner in that it more concisely expresses the developer's intent
without introducing external dependencies.
Moreover, I would further argue that use of boost::noncopyable has a
bit of a problem, in addition to being possibly misleading in its
name. The problem is that if you derive from boost::noncopyable, and
then later do want to add one of the members not automatically
provided by the compiler, then the member that is added will contain
an error that, while it has no effect in this particular case, could
be flagged by the compiler if warning levels are set high enough, and
will certainly be flagged by a lint-like tool. The problem is that
the copy ctor and assignment operator for boost::noncopyable are
declared as private and not implemented. Thus, even if you later do
decide to provide one of these operations in your derived class, you
cannot ever copy or assign the boost::noncopyable base class. In that
sense your copy ctor or assignment operator is technically incorrect,
and this error could well be flagged by some tools. For a base class
with any data members this would be a real potential error, and it is
only not so for boost::noncopyable due to the fact that the class has
no data members.
Thus, the newly proposed use of explicit would accomplish the same end
as use of boost::noncopyable, but without the possibility of
generating warning messages about an incorrect copy ctor or assignment
operator. And, yes, that warning could be safely ignored, in this
particular case, but I generally do not like to see warnings ignored
since doing so may lead to ignoring real problems.
On the basis of the new use of explicit being cleaner and clearer, not
introducing any external dependencies, and not making the copy ctor or
assignment operator, if later implemented, technically incorrect in a
way that could well be flagged by certain tools, I would have to say
that, IMHO, the new use of explicit is a better solution. Since
boost::noncopyable exists to solve a real problem, and has been widely
used, I would say that the C++ committee might be moved to take a look
at this issue.
I would further say that I see no reason why boost::noncopyable, the
new use of explicit, and the idiom of private declaration with no
definition cannot coexist, especially since the latter idiom is
somewhat different in its effect because with either of the first two
methods a developer may later merely declare and implement a member if
and as necessary. With the private declaration and no definition
idiom, doing this would generate a compiler error if a later developer
simply added one of the prohibited members, and in that sense it is a
slightly stronger statement of developer intent, and one that the
compiler can assist in enforcing. Thus, each of these idioms is
slightly different, and may be appropriately used in different
situations, although there is a good deal of overlap in their meaning.
This, I think, is a good thing, and in keeping with the spirit of C++
allowing developers to solve the same problem in a way that best fits
both their needs and their own programming style.
Randy.
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Adam H. Peterson" <ahp6@email.byu.edu>
Date: Mon, 12 Aug 2002 17:52:27 GMT Raw View
> We all seem to be in agreement that boost::noncopyable and the
> proposed new use of explicit solve the exact same problem, i.e., they
> prevent the compiler from automatically generating unwanted members
> for a class, and both allow the developer to later provide those
> members if and as they become desirable. So far, so good.
>
> However, I would argue that the proposed new use of explicit is
> cleaner in that it more concisely expresses the developer's intent
> without introducing external dependencies.
I'll take the counter-argument. Which looks cleaner to you?
class Complicated1 : noncopyable {};
or
explicit class Complicated2 {};
Perhaps this is a judgement call, but it looks to me a lot more obvious that
there will be issues with copying Complicated1 than it does with
Complicated2, at least in the header file. The diagnostic generated for
violating these semantics will probably be pretty similar in either case.
>
> Moreover, I would further argue that use of boost::noncopyable has a
> bit of a problem, in addition to being possibly misleading in its
> name. The problem is that if you derive from boost::noncopyable, and
> then later do want to add one of the members not automatically
> provided by the compiler, then the member that is added will contain
> an error that, while it has no effect in this particular case, could
> be flagged by the compiler if warning levels are set high enough, and
> will certainly be flagged by a lint-like tool. The problem is that
> the copy ctor and assignment operator for boost::noncopyable are
> declared as private and not implemented. Thus, even if you later do
> decide to provide one of these operations in your derived class, you
> cannot ever copy or assign the boost::noncopyable base class. In that
> sense your copy ctor or assignment operator is technically incorrect,
> and this error could well be flagged by some tools. For a base class
> with any data members this would be a real potential error, and it is
> only not so for boost::noncopyable due to the fact that the class has
> no data members.
Well, I must make a deep personal confession that I have never used Lint or
anything like it. I've frequently meant to, but have not found the time or
a compelling need.
That said, I would say that if such a tool would generate such a diagnostic
that could not be suppressed, it would be in error. It is entirely
conceivable that a user-defined type may define assignment or copy to do any
number of things, as long as it has a semantically consistent interface.
What would lint say if my class were using handle/body and simply forwarded
operator=() to body->makeSameAs()? (I am partly asking because I don't
know, having never used them.)
I would especially think that not calling _private_ data members and base
classes's op= or copy ctor would be reasonable, since I may have to jump
through any number of hoops to construct a consistent interface. I know
this is the case for my NeuralNet objects that are composed of a
directed-graph-like set of subobjects. There is no mapping between
NeuralNet::operator= and Node::operator=. Such a mapping doesn't make sense
when the internal graph has to be rebuilt to match the parameter's internal
structure.
>
> Thus, the newly proposed use of explicit would accomplish the same end
> as use of boost::noncopyable, but without the possibility of
> generating warning messages about an incorrect copy ctor or assignment
> operator. And, yes, that warning could be safely ignored, in this
> particular case, but I generally do not like to see warnings ignored
> since doing so may lead to ignoring real problems.
I personally don't like warnings on safe behavior, especially if they cannot
be suppressed. The result is a developer using a perfectly valid construct
and living with a list of warnings every time he compiles. One of these
days, he's going to skip a legitimate warning in that long list. I have a
similar gripe about signed/unsigned warnings when the conversion is formally
specified by the language and a cast just makes the code more brittle.
>
> On the basis of the new use of explicit being cleaner and clearer, not
> introducing any external dependencies, and not making the copy ctor or
> assignment operator, if later implemented, technically incorrect in a
> way that could well be flagged by certain tools, I would have to say
> that, IMHO, the new use of explicit is a better solution. Since
> boost::noncopyable exists to solve a real problem, and has been widely
> used, I would say that the C++ committee might be moved to take a look
> at this issue.
I'm not convinced that boost::noncopyable exhibits any serious shortcomings
in solving the problem. What I'd rather see is having it become
std::noncopyable in C++0x. If this were to happen, it would be all the
easier for lint-like tools to fix their false positive warnings by
recognizing the standard way to make a class noncopyable and the standard
way to overrule it.
>
> I would further say that I see no reason why boost::noncopyable, the
> new use of explicit, and the idiom of private declaration with no
> definition cannot coexist, especially since the latter idiom is
> somewhat different in its effect because with either of the first two
> methods a developer may later merely declare and implement a member if
> and as necessary.
I agree that these constructs may all coexist. But I still don't see where
explicit class solves any problem better than current methodology,
especially if noncopyable becomes part of the standard. Assuming this comes
about, if some compiler writer wanted to, they could make inheriting from
std::noncopyable behave exactly the same way you want explicit class to
behave, with the added benefits that, 1) the grammar of c++ doesn't have to
be changed, and 2) we are spared from having yet another keyword overloaded.
> With the private declaration and no definition
> idiom, doing this would generate a compiler error if a later developer
> simply added one of the prohibited members, and in that sense it is a
> slightly stronger statement of developer intent, and one that the
> compiler can assist in enforcing.
I'm not sure I follow. If you're talking about someone adding the member in
a derived class, I don't see any difference between the approaches. If
you're talking about adding the member in the class with the privately
declared copy-oriented members, than I would assume three things about this
developer. 1) This developer, in modifying the class definition, is a
maintainer of some sort to the class. 2) Before starting such an
undertaking, he has read the class definition as currently constituted. He
will know that the class is noncopyable/explicit as this will be one of the
first things he reads in the definition. Or he will see the private
declarations and know exactly how to override the original developer's
choice. 3) By undertaking to modify this definition, he hopefully has some
idea what the ramifications are, or else he's a monkey trying to type
Shakespeare on a teletype.
But arguing the merits of private declaration doesn't do anything to
strengthen the position that explicit class should be added to the language.
> Thus, each of these idioms is
> slightly different, and may be appropriately used in different
> situations, although there is a good deal of overlap in their meaning.
I agree that there are pros and cons between boost::noncopyable and private
declaration, making it desirable to choose one or the other in different
circumstances (which I would think mostly depend on which developer is doing
the choosing). But I don't see any real differences between noncopyable and
explicit class. I also think it would be detrimental to have two camps of
programmers doing essentially the same thing with different syntaxes. I
think this would do more harm than good to people trying to learn C++
(which, IIRC, was a principle motivation for introducing this in the first
place).
> This, I think, is a good thing, and in keeping with the spirit of C++
> allowing developers to solve the same problem in a way that best fits
> both their needs and their own programming style.
C++ provides great power as a multiparadigm programming language.
Multiparadigm programming is one of the biggest reasons I stick with C++
even after all its nasty quirks. When there is more than one way to do
something, it is usually because the different ways to do things in
different paradigms. boost::noncopyable and explicit class are both
solutions within a single paradigm of programming, though. TIMTOWTDI for
its own sake is, IMO, not the spirit of C++. It is more the spirit of Perl,
and Perl has felt the effects of it.
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: rmaddox@isicns.com (Randy Maddox)
Date: Tue, 13 Aug 2002 15:06:10 GMT Raw View
"Adam H. Peterson" <ahp6@email.byu.edu> wrote in message news:<aj8rmd$t18$1@acs2.byu.edu>...
> I'll take the counter-argument. Which looks cleaner to you?
>
> class Complicated1 : noncopyable {};
>
> or
>
> explicit class Complicated2 {};
>
> Perhaps this is a judgement call, but it looks to me a lot more obvious that
> there will be issues with copying Complicated1 than it does with
> Complicated2, at least in the header file. The diagnostic generated for
> violating these semantics will probably be pretty similar in either case.
>
Perhaps this is a judgement call, but since the net effect on both of
your Complicated classes is not that there are issues with copying,
but rather only that the compiler will not generate any default
members to do so, I would have to say that the latter is clearer.
Also note that the latter introduces no external dependencies, while
the former does.
> Well, I must make a deep personal confession that I have never used Lint or
> anything like it. I've frequently meant to, but have not found the time or
> a compelling need.
If you write code you should, IMHO, be using every tool at your
disposal to help ensure its correctness. This includes compiling with
warning levels set to the max, using Lint or one if its variants, and
using run-time analysis tools like Purify or the like. And of course
that's all just on the development side. I'm assuming a separate QA
role after that.
Humans make errors, so the only way to not code errors is to not write
code. The best way to ensure that as many errors as possible are
caught is to use every tool we have available.
> I personally don't like warnings on safe behavior, especially if they cannot
> be suppressed. The result is a developer using a perfectly valid construct
> and living with a list of warnings every time he compiles. One of these
> days, he's going to skip a legitimate warning in that long list. I have a
> similar gripe about signed/unsigned warnings when the conversion is formally
> specified by the language and a cast just makes the code more brittle.
Most tools can be configured to not generate warnings in certain
cases, but the reason so many constructs that are commonly used are
flagged is that these uses are also a common source of errors. Sure
there is a default conversion between signed and unsigned, but that
conversion is something that should be done only deliberately, and
only after checking to be sure there is no issue. What if you have a
function that takes an unsigned parameter and you pass it a negative
int value? The result is almost certainly an unexpectedly large
positive value, which may very well be an error. I would certainly
prefer to see such usage flagged, even if a careful inspection of the
code shows that in a given particular case it is correct, which should
then be documented in the code. Better safe than sorry I say.
> I'm not convinced that boost::noncopyable exhibits any serious shortcomings
> in solving the problem.
Well, yes, but you are also apparently not convinced of the value of
tools that are very widely used, so perhaps the shortcomings I
mentioned are more important to some than they may be to you.
Randy.
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Ken Thomases <ken@spamnot.codeweavers.com>
Date: Tue, 13 Aug 2002 17:48:20 GMT Raw View
Adam H. Peterson wrote:
> Here's my argument against:
>
> I don't see how explicit is at all different from private inheritance from
> boost::noncopyable. Either suppresses automatic copy constructor and
> assignment constructor generation, and either can be explicitly overridden.
> The only difference I can see is that explicit also suppresses the automatic
> generation of a default constructor. I see this as a non-issue, since that
> will be suppressed if you declare any constructor yourself anyways. And if
> you don't declare any constructor, why would you want to suppress default
> constructor generation? The (extremely few, and almost academic) cases I
> can think of where this would be desirable are easily handled by private
> constructor declaration.
>
> So, really, what does explicit class buy us anyway? In my view, nothing,
> and certainly not enough to modify the language.
Is it true that providing a constructor causes suppression of
compiler-supplied destructor? I don't think it is. I just tried this
in CodeWarrior 8.1:
#include <string>
#include <vector>
class MyTest
{
public:
MyTest() : m_string("blat"), m_vector(10) { }
MyTest(const MyTest& in_other) :
m_string(in_other.m_string), m_vector()
{ m_vector.push_back(m_string); }
private:
const std::string m_string;
std::vector<std::string> m_vector;
};
int main()
{
MyTest foo;
MyTest bar(foo);
// MyTest gub;
// gub = foo; // error
}
I figure those constructors have enough meat to be clearly non-trivial.
The string is const to test suppression of compiler-supplied
assignment operator. It compiles quite nicely. Now, clearly, for this
code to be legal the compiler must be getting a destructor from
somewhere. Right? Neither object's m_string or m_vector are allowed to
leak, are they?
For kicks, I tried making MyTest privately inherit boost::noncopyable.
Still compiled, although the compiler error if I uncommented the gub
lines changed from "using implicit copy assignment for class with const
or reference member" to "illegal access to private/protected member".
With explicit class, no destructor would be provided. The compiler
would produce errors for almost any instantiation of the class (except,
dynamically allocated on the heap and never deleted). What would be the
value of this? It would remind a programmer who suffered a lapse in
concentration that their complex class needed a programmer-supplied
destructor up to the task. Better a compiler error than a
compiler-supplied destructor which masks the problem.
Ken
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Adam H. Peterson" <ahp6@email.byu.edu>
Date: Tue, 13 Aug 2002 18:53:05 GMT Raw View
"Randy Maddox" <rmaddox@isicns.com> wrote in message
news:8c8b368d.0208130527.3714ac3c@posting.google.com...
> "Adam H. Peterson" <ahp6@email.byu.edu> wrote in message
news:<aj8rmd$t18$1@acs2.byu.edu>...
> > I'll take the counter-argument. Which looks cleaner to you?
> >
> > class Complicated1 : noncopyable {};
> >
> > or
> >
> > explicit class Complicated2 {};
> >
> > Perhaps this is a judgement call, but it looks to me a lot more obvious
that
> > there will be issues with copying Complicated1 than it does with
> > Complicated2, at least in the header file. The diagnostic generated for
> > violating these semantics will probably be pretty similar in either
case.
> >
>
> Perhaps this is a judgement call, but since the net effect on both of
> your Complicated classes is not that there are issues with copying,
> but rather only that the compiler will not generate any default
> members to do so, I would have to say that the latter is clearer.
I don't understand the utility of suppressing the automatic compiler
generation of copy oriented members in any class unless there are issues
involved with copying it. If the class can be safely copied, then either
the compiler generated copy constructor and assignment operator were correct
or the developer replaced one or both with versions that were correct. In
neither case do they need to be explicitly suppressed. So when would you
use either of these constructs unless the class is not designed to be
copied?
> Also note that the latter introduces no external dependencies, while
> the former does.
Well, perhaps I am less afraid of external dependencies than you are, but my
code is very heavily externally dependent on the C++ standard library, and I
think there isn't very much code that isn't. I would hardly call use of the
C++ standard library an external dependency. And whether we call it that or
not, I feel that anything that can be solved in the standard library doesn't
justify a core language change.
>
> > Well, I must make a deep personal confession that I have never used Lint
or
> > anything like it. I've frequently meant to, but have not found the time
or
> > a compelling need.
>
> If you write code you should, IMHO, be using every tool at your
> disposal to help ensure its correctness. This includes compiling with
> warning levels set to the max, using Lint or one if its variants, and
> using run-time analysis tools like Purify or the like. And of course
> that's all just on the development side. I'm assuming a separate QA
> role after that.
Unfortunately Lint and Purify are not at my disposal. They are very
expensive and I am not in charge of the budget for development tools. If
they were at my disposal, I would use them.
Furthermore, I am under the burden of working with Visual C++ (not your
fault, just unfortunate reality), so I can't set the warnings to the maximum
because if I do, the standard library generates thousands of warnings (all
of them false positives, I'm sure). So I set the warning level as high as I
can get without that happening.
Anyway, I would be very surprised if any compiler would generate any type of
diagnostic at all for a copy constructor that is well formed, but "dubious"
in the way you describe. Perhaps Lint and Purify would (I don't know), but
I would be surprised at that as well. User defined copy constructors and
assignment operators are invariably provided _because_ the simplistic
assumptions that an automatic tool makes about them are wrong. So a tool
that tells me my copy constructor is wrong because it doesn't look enough
like the one that would have been automatically generated anyway just
doesn't seem to me like it would be telling me anything useful. Especially
since it seems to me that the worst gotchas associated with assignment
operators usually revolve around exception safety, and I would be very
surprised if Lint would be able to help me out on that front.
>
> Humans make errors, so the only way to not code errors is to not write
> code. The best way to ensure that as many errors as possible are
> caught is to use every tool we have available.
I will give you no argument here.
>
> > I personally don't like warnings on safe behavior, especially if they
cannot
> > be suppressed. The result is a developer using a perfectly valid
construct
> > and living with a list of warnings every time he compiles. One of these
> > days, he's going to skip a legitimate warning in that long list. I have
a
> > similar gripe about signed/unsigned warnings when the conversion is
formally
> > specified by the language and a cast just makes the code more brittle.
>
> Most tools can be configured to not generate warnings in certain
> cases,
Perhaps your experience with most tools has been radically different from
mine.
> but the reason so many constructs that are commonly used are
> flagged is that these uses are also a common source of errors. Sure
> there is a default conversion between signed and unsigned, but that
> conversion is something that should be done only deliberately, and
> only after checking to be sure there is no issue.
I would give you no argument if there were a way to indicate to the tool
that the conversion is intended. Unfortunately, we do not have an
unsigned_cast<>, and a static_cast<> is liable to cause breakage during
maintenance. So I rely on the language defined conversions as the next best
thing. Not perfect, but not an error either.
> What if you have a
> function that takes an unsigned parameter and you pass it a negative
> int value? The result is almost certainly an unexpectedly large
> positive value, which may very well be an error.
Yes, it could be, I suppose. However, in my opinion, the proper mechanism
for checking input values is design by contract. What if I pass an invalid
handle? There are entire classes of errors that can be termed input errors,
and checking signed/unsigned mismatches only catches a handful of them.
Anyway, if I'm passing a negative number to a function in an unsigned
parameter, I seriously doubt I've thought the code through at all. That
just doesn't happen very often in my experience. What happens more often is
that I have a positive number in a signed integer, generated by an
algorithmic process that is guaranteed to end with a nonnegative number, and
I pass _that_ to my unsigned function. There is absolutely nothing wrong
with that, especially if I have used design by contract to ensure that the
process that is supposed to produce a nonnegative value fulfilled its
contract.
> I would certainly
> prefer to see such usage flagged, even if a careful inspection of the
> code shows that in a given particular case it is correct, which should
> then be documented in the code. Better safe than sorry I say.
Sure, if the diagnostic would come up only once, the code verified correct,
the diagnostic dismissed, and forever forgotten. But that's not how it
works. The warning comes up every time you compile, and the compiler
doesn't read your comments to make sure you haven't considered it.
So one day, you get a list of 36 warnings instead of 34. Are you liable to
notice? Probably not. So you have two legitimate warnings about use of
uninitialized variables or some such, mixed among 34 signed/unsigned
mismatch or some other nonsense warnings, and the baby gets thrown out with
the bathwater.
>
> > I'm not convinced that boost::noncopyable exhibits any serious
shortcomings
> > in solving the problem.
>
> Well, yes, but you are also apparently not convinced of the value of
> tools that are very widely used, so perhaps the shortcomings I
> mentioned are more important to some than they may be to you.
I didn't say that. I think the tools are valuable, if available, and if
they don't produce false positives (and perhaps even if they do, depending
on the severity). In any event, I don't see how the use of explicit class
would help tools at all. They can recognize (proposed) std::noncopyable
just as easily as they can recognize (proposed) explicit class. So whether
you or I value tools or not, explicit class doesn't add anything, unless you
have a peculiar phobia of using the standard library and no such qualms
about mangling the core language.
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: John Nagle <nagle@animats.com>
Date: Tue, 13 Aug 2002 20:45:59 GMT Raw View
Adam H. Peterson wrote:
> "Randy Maddox" <rmaddox@isicns.com> wrote in message
> news:8c8b368d.0208130527.3714ac3c@posting.google.com...
>
>>"Adam H. Peterson" <ahp6@email.byu.edu> wrote in message
>>
> news:<aj8rmd$t18$1@acs2.byu.edu>...
>
>>>I'll take the counter-argument. Which looks cleaner to you?
>>>
>>>class Complicated1 : noncopyable {};
I'd be fine with that if you could write
class nocopyable such that you got a coherent message
at compile time if you tried to do a copy. Someone
pointed out that Boost's "noncopyable" can result in
a copyable subclass, so there's apparently a problem.
John Nagle
Animats
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Ken Thomases <ken@spamnot.codeweavers.com>
Date: Tue, 13 Aug 2002 23:02:15 GMT Raw View
First, let me say that I'm gratified that my suggestion generated lively
and interesting discussion. I half thought it would be ignored.
Randy Mattox wrote:
>We all seem to be in agreement that boost::noncopyable and the
>proposed new use of explicit solve the exact same problem, i.e., they
>prevent the compiler from automatically generating unwanted members
>for a class, and both allow the developer to later provide those
>members if and as they become desirable. So far, so good.
>
>However, I would argue that the proposed new use of explicit is
>cleaner in that it more concisely expresses the developer's intent
>without introducing external dependencies.
Adam H. Peterson wrote:
> I'll take the counter-argument. Which looks cleaner to you?
>
> class Complicated1 : noncopyable {};
>
> or
>
> explicit class Complicated2 {};
>
> Perhaps this is a judgement call, but it looks to me a lot more obvious that
> there will be issues with copying Complicated1 than it does with
> Complicated2, at least in the header file. The diagnostic generated for
> violating these semantics will probably be pretty similar in either case.
As you say, a judgement call. My judgement is that the latter looks
cleaner. In part because, as Randy pointed out, noncopyable is a
misnomer. Mostly, though, it just puts to rest the whole question of
what if anything the compiler would supply and what the various rules
are for which things are suppressed by which developer-supplied
declarations. I know, it's really not that complicated and any serious
C++ programmer needs to master these rules (I believe I have -- I
think :-). It just seems more straightforward to set-it-and-forget-it.
Adam H. Peterson wrote:
> I'm not convinced that boost::noncopyable exhibits any serious shortcomings
> in solving the problem. What I'd rather see is having it become
> std::noncopyable in C++0x. If this were to happen, it would be all the
> easier for lint-like tools to fix their false positive warnings by
> recognizing the standard way to make a class noncopyable and the standard
> way to overrule it.
I agree that promoting noncopyable from boost:: to std:: makes it
substantially less problematic. (By the way, what would be a good
standard header to contain std::noncopyable? I suppose <noncopyable>.)
We definitely shouldn't be stuck choosing between using a third-party
library or rolling our own solution for such a common need. Obviously,
I still prefer explicit class over even std::noncopyable.
Also, as Randy pointed out, noncopyable is possibly a misnomer since it
really means not-implicitly-copyable. And this gets to the meat of the
matter. What the programmer really wants when s/he uses noncopyable is
to suppress implicit behavior, so why not use the term "explicit"?
Randy Mattox wrote:
>I would further say that I see no reason why boost::noncopyable, the
>new use of explicit, and the idiom of private declaration with no
>definition cannot coexist, especially since the latter idiom is
>somewhat different in its effect because with either of the first two
>methods a developer may later merely declare and implement a member if
>and as necessary.
Adam H. Peterson wrote:
> I agree that these constructs may all coexist. But I still don't see where
> explicit class solves any problem better than current methodology,
> especially if noncopyable becomes part of the standard. Assuming this comes
> about, if some compiler writer wanted to, they could make inheriting from
> std::noncopyable behave exactly the same way you want explicit class to
> behave, with the added benefits that, 1) the grammar of c++ doesn't have to
> be changed, and 2) we are spared from having yet another keyword overloaded.
I don't really consider it much of an overload of the keyword (not like,
say, "static"). In other contexts (including the proposed explicit cast
operator syntax), explicit means the compiler would do something
implicitly for me, but I want to suppress that behavior.
In general, I think it's a pretty good principle that whenever the
compiler provides implicit behavior (especially, potentially surprising
or dangerous behavior) that it provide a way to suppress it.
I'm somewhat surprised that when "explicit" was added to the language it
wasn't extended for this purpose. The standard authors were clearly
examining the issue of how to avoid unwanted compiler-supplied
behaviors, and compiler-supplied functions must be high on the list. I
would have thought this issue would have come up. Maybe it did and was
dismissed. I'm more than willing to recognize that this solves a
problem that has other, albeit idiomatic, solutions. It's not strictly
necessary, just seems more consistent and cleaner.
Adam H. Peterson wrote:
> I agree that there are pros and cons between boost::noncopyable and private
> declaration, making it desirable to choose one or the other in different
> circumstances (which I would think mostly depend on which developer is doing
> the choosing). But I don't see any real differences between noncopyable and
> explicit class. I also think it would be detrimental to have two camps of
> programmers doing essentially the same thing with different syntaxes.
> I think this would do more harm than good to people trying to learn C++
> (which, IIRC, was a principle motivation for introducing this in the first
> place).
Well, maybe not a _principle_ motivation, but...
Imagine a class of newbie C++ programmers. They've done "Hello, World",
they've implemented a couple of simple value-semantics,
just-barely-more-than-POD classes, and the prof. teaches them that
they've benefited from certain compiler-supplied stuff behind the
scenes. The prof. then explains that there are certain dangers and
pitfalls to this compiler-supplied stuff and says:
"To avoid these pitfalls, put the keyword explicit in front of your
class declaration."
or
"To avoid these pitfalls, include the header file <noncopyable>, and
make your class inherit [oh yeah, have they gotten to inheritance?] from
std::noncopyable. You should inherit private instead of public because
you're not establishing an IS-A relationship, you're just inheriting
implementation. Err, what implementation? Well, the implementation of
turning off the compiler-supplied stuff."
And I think the relative complexity of those two statements is
ultimately reflected, on some level, in the brains of experienced C++
programmers. Perfectly good neurons gone to waste. It's too late for
us, but think of the children! :-)
Ken
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Wed, 14 Aug 2002 04:44:49 GMT Raw View
In article <ajbjl2$4qm$1@acs2.byu.edu>, Adam H. Peterson
<ahp6@email.byu.edu> writes
>Unfortunately Lint and Purify are not at my disposal. They are very
>expensive and I am not in charge of the budget for development tools. If
>they were at my disposal, I would use them.
Go to www.gimpel.com and check the prices PC-lint one workstation
licence is $239. Yes Purify is rather more expensive at $750 and is
arguably less essential. However I would bet large money that both
products would pay for themselves in six months and, in the case of
PC-Lint, a very few weeks. The only trouble is that most source code is
of such poor quality that you have to very slowly wind up the level of
checking with PC-Lint to prevent being swamped with the many (genuine)
defects in the code.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Allan_W@my-dejanews.com (Allan W)
Date: Mon, 5 Aug 2002 21:48:39 GMT Raw View
Gennaro Prota <gennaro_prota@yahoo.com> wrote:
[Would like to use this syntax to declare that a function won't be defined:]
> class A {
> void * operator new (std::size_t) = false;
> };
This looks a lot like an abstract function!
class B {
void * opnew(std::size_t) = 0;
};
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Adam H. Peterson" <ahp6@email.byu.edu>
Date: Wed, 14 Aug 2002 11:34:28 CST Raw View
[note to moderator: I submitted this message earlier without getting a
confirmation. If this turns out to be a duplicate, you know what to do ;).]
<snip>
> As you say, a judgement call. My judgement is that the latter looks
> cleaner. In part because, as Randy pointed out, noncopyable is a
> misnomer. Mostly, though, it just puts to rest the whole question of
> what if anything the compiler would supply and what the various rules
> are for which things are suppressed by which developer-supplied
> declarations. I know, it's really not that complicated and any serious
> C++ programmer needs to master these rules (I believe I have -- I
> think :-). It just seems more straightforward to set-it-and-forget-it.
Well, I believe this thread has demonstrated that reasonable minds can
differ on this subject. I think both our opinions have been expressed and
we each have probably advocated them rather well.
I still think that explicit class solves a nonproblem, and I'm sure you
still think it's worthwhile. Without saying which is correct, I'll just
venture a prediction that the standards committee won't see this as filling
a major deficiency in the language that justifies a change to the core of
C++.
<snip>
> Also, as Randy pointed out, noncopyable is possibly a misnomer since it
> really means not-implicitly-copyable. And this gets to the meat of the
> matter. What the programmer really wants when s/he uses noncopyable is
> to suppress implicit behavior, so why not use the term "explicit"?
Well, the misnomer thing is certainly addressable without changing the core
language. If you like, we could make it something like:
class Complicated : use_explicit_copy {};
I would probably put it in a header called <generic> or <design> along with
is_a<> and other templates of a design-oriented nature.
<snip>
> I don't really consider it much of an overload of the keyword (not like,
> say, "static"). In other contexts (including the proposed explicit cast
> operator syntax), explicit means the compiler would do something
> implicitly for me, but I want to suppress that behavior.
I disagree. I believe it would be every bit as overloaded as static. While
explicit means "compiler, don't do such and such", static means
"singleton-bound to containing entity". Semantically, they both have a
consistent meaning under the right interpretation. Yet syntactically they
would both have multiple disparate uses. So overloading the keyword would
not necessarily be the end of the world, yet I still think it would be
confusing to people learning the core language. Just because you and I see
the semantic unity behind the different uses doesn't mean it would be
intuitive to someone learning the language.
So, in my humble opinion, I would prefer to see syntactic overloading only
used to solve a real problem that doesn't already have a good solution
without it.
>
> In general, I think it's a pretty good principle that whenever the
> compiler provides implicit behavior (especially, potentially surprising
> or dangerous behavior) that it provide a way to suppress it.
Which we have. We actually have two ways to suppress it. First, we have
boost::noncopyable, and second, we have private declaration. I'm inclined
against another solution unless it has substantial benefits over what is
already available.
>
> I'm somewhat surprised that when "explicit" was added to the language it
> wasn't extended for this purpose. The standard authors were clearly
> examining the issue of how to avoid unwanted compiler-supplied
> behaviors, and compiler-supplied functions must be high on the list. I
> would have thought this issue would have come up. Maybe it did and was
> dismissed. I'm more than willing to recognize that this solves a
> problem that has other, albeit idiomatic, solutions. It's not strictly
> necessary, just seems more consistent and cleaner.
I can't speak to that. I wasn't involved in the decision. I can speculate
that if it was discussed, the committee may have decided that as C++ is
already a very complicated language just to parse (although explicit class
probably wouldn't really hurt parsing), let alone provide correct runtime
behavior for (to the point where we're anticipating our Technical
Corrigendum only shortly after we're getting our first correct
implementations of the language as presently constituted) that a substantve
benefit would be needed to justify adding such a complexity. But, like I
say, this is all uninformed speculation framed from within my point of view.
<snip>
> Imagine a class of newbie C++ programmers. They've done "Hello, World",
> they've implemented a couple of simple value-semantics,
> just-barely-more-than-POD classes, and the prof. teaches them that
> they've benefited from certain compiler-supplied stuff behind the
> scenes. The prof. then explains that there are certain dangers and
> pitfalls to this compiler-supplied stuff and says:
>
> "To avoid these pitfalls, put the keyword explicit in front of your
> class declaration."
>
> or
>
> "To avoid these pitfalls, include the header file <noncopyable>, and
> make your class inherit [oh yeah, have they gotten to inheritance?] from
> std::noncopyable. You should inherit private instead of public because
> you're not establishing an IS-A relationship, you're just inheriting
> implementation. Err, what implementation? Well, the implementation of
> turning off the compiler-supplied stuff."
>
> And I think the relative complexity of those two statements is
> ultimately reflected, on some level, in the brains of experienced C++
> programmers. Perfectly good neurons gone to waste. It's too late for
> us, but think of the children! :-)
Well, one of these descriptions explains more than it needs to. I could
easily turn the tables around like this:
"To avoid these pitfalls, put the keyword explicit in front of your class
declaration. This will prevent your class from being copyable and
assignable unless you implement a copy constructor and assignment operator.
By the way, to override it, bear in mind that a copy constructor should take
a const parameter by reference to promote const correctness and prevent
infinite recursion. Also, if you use explicit and don't provide a copy
constructor or assignment operator, this explicit property will transfer to
all subclasses and all classes that contain yours as a datamember by
default."
or
"To avoid these pitfalls, use the <design> header and apply the noncopyable
attribute to your class."
Someone learning C++ will have to learn the syntax either way, and they will
take what's given them at face value. If it turns out that a procedure they
were taught to apply as a recipe happens to unify with more general concepts
such as private inheritance or generic attributes later on, the language
will just seem all the more elegant (until they get to Koenig lookup :) ).
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: rmaddox@isicns.com (Randy Maddox)
Date: Wed, 14 Aug 2002 16:50:22 GMT Raw View
"Adam H. Peterson" <ahp6@email.byu.edu> wrote in message news:<ajbjl2$4qm$1@acs2.byu.edu>...
> "Randy Maddox" <rmaddox@isicns.com> wrote in message
> news:8c8b368d.0208130527.3714ac3c@posting.google.com...
> > "Adam H. Peterson" <ahp6@email.byu.edu> wrote in message
> news:<aj8rmd$t18$1@acs2.byu.edu>...
> Furthermore, I am under the burden of working with Visual C++ (not your
> fault, just unfortunate reality), so I can't set the warnings to the maximum
> because if I do, the standard library generates thousands of warnings (all
> of them false positives, I'm sure). So I set the warning level as high as I
> can get without that happening.
I too have worked with the MSVC++ compiler, although at this point
calling it a C++ compiler is a bit of a stretch since it fails to
conform in so many regards, and have found the following technique
useful in allowing me to turn up the compiler warning level without
generating a bazillion warnings. It's a bit tedious, but every place
you include anything other than your own header files surround the
inclusion with pragmas to turn down and then restore the warning
level. For example:
#pragma warning (push, 2)
#include <MS-supplied-header-file>
#pragma warning (pop)
This will allow you to compile your own code with a higher warning
level than is practically possible for the MS-supplied header files.
> > > I'm not convinced that boost::noncopyable exhibits any serious
> shortcomings
> > > in solving the problem.
> >
> > Well, yes, but you are also apparently not convinced of the value of
> > tools that are very widely used, so perhaps the shortcomings I
> > mentioned are more important to some than they may be to you.
>
> I didn't say that. I think the tools are valuable, if available, and if
> they don't produce false positives (and perhaps even if they do, depending
> on the severity). In any event, I don't see how the use of explicit class
> would help tools at all. They can recognize (proposed) std::noncopyable
> just as easily as they can recognize (proposed) explicit class. So whether
> you or I value tools or not, explicit class doesn't add anything, unless you
> have a peculiar phobia of using the standard library and no such qualms
> about mangling the core language.
Well, boost::noncopyable, as indicated by the namespace boost rather
than std, is not a part of the standard C++ language.
Randy.
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Daniel Miller <daniel.miller@tellabs.com>
Date: Wed, 14 Aug 2002 21:25:51 GMT Raw View
John Nagle wrote:
> Adam H. Peterson wrote:
>
>> "Randy Maddox" <rmaddox@isicns.com> wrote in message
>> news:8c8b368d.0208130527.3714ac3c@posting.google.com...
>>
>>> "Adam H. Peterson" <ahp6@email.byu.edu> wrote in message
>>>
>> news:<aj8rmd$t18$1@acs2.byu.edu>...
>>
>>>> I'll take the counter-argument. Which looks cleaner to you?
>>>>
>>>> class Complicated1 : noncopyable {};
>>>
>
>
> I'd be fine with that if you could write
> class nocopyable such that you got a coherent message
> at compile time if you tried to do a copy. Someone
> pointed out that Boost's "noncopyable" can result in
> a copyable subclass, so there's apparently a problem.
I am beginning to suspect that the presence or absence of problems is
not necessarily what is on some people's minds. Rather, an implicit
debate concerning control of ideology is occurring (and has been
occurring for some time now in the C++ community).
One ideology is that the C++ language (and the C language before
that) should move as much feature-set as possible to libraries, even if
the library behavior of that feature-set has warts. Only if no
library-based solution exists in any form would inclusion of the feature
into the language proper be considered.
The other ideology is that the C++ language itself should sanely
handle the semantics natural to classes, to objects, and to
parameterized types which designers (e.g., application designers,
library designers) wish to express without additional helper libraries
to make up for deficiencies in the expressivity of the C++ language itself.
Back in K&R C, there naturally was a decision point at which the
language designers could place file input/output either within the
language itself as other languages of that era did (e.g., Pascal's
writeln & readln) or within a library which accompanied the language
(e.g., the fopen/fclose/f-series functions) or deferred to the operating
system (e.g., what became the POSIX system calls). Although I would
like to read a posting on this history by Kernighan & Ritchie, I have
always heard that the primary deciding factor was that input/output was
outside of the minimalist control language proper and was outside of the
minimalist in-RAM data/declaration/definition language proper, thus
input/output was intentionally separated from the language proper,
leaving the matter to one, the other, or both of the other two options.
(Both, as it turned out for C over the years: the C standard library
as well as POSIX.1-series.) If input/output were brought within the
language syntax proper (a la Pascal's writeln & readln), the possible
feature-set supportable would be either the same feature-set as the
library form of input/output or at best only a slight superset---neither
of which was deemed to justify the inflexibility.
But the trend that we see in portions of Boost appears to me to
deviate from this time-honored library-versus-language decision-making
technique significantly. With the likes of boost::noncopyable we see a
library attempting to manipulate behavior of the language proper,
behavior which is under the language's control, behavior about which the
library can provide only fragile hints with which all subsequent C++
code within that compilation unit is hoped to play nicely (and not
override/disrupt subtly), and most importantly behavior which is the
purview of the language-proper: generation of default member-functions.
True, boost::noncopyable is not the first such class to be written, as
there have been noncopyable classes from which to inherit floating
around in the C++ community for around a decade now. But the difference
now is that boost::noncopyable could be standardized as *the* *only*
*official* C++ way of expressing such concepts, instead of merely the
hack-with-warts that such classes are whose reason to exist is: in lieu
of such a feature in the language proper. A std::noncopyable class
would be C++200x's statement on the topic, leaving hope for a fix to a
std::noncopyable's warts to some C++201x standard or leaving hope for a
fix to some new post-C++ language.
Let us all re-examine which features should be placed in a standard
library because that is where those features are best expressed as well
as re-examining the exact explicit set of inputs which we use to arrive
at that decision. Let us all also re-examine which features regard the
behavior C++ language proper, for those features governing the language
itself are best placed in the language itself, not in some library of
fragile hacks which futilely attempt to make up for deficiencies in the
language itself.
This re-examination applies not only to merely boost::noncopyable,
but also to all of the frontiers of template meta-programming &
(near-)reflection which again are solely in a fragile library of
experimental hacks instead of the language proper. I applaud Loki's &
Boost's academic-research-style experimentation/prototype/mock-up of
this very interesting what-if look at what some next-generation post-C++
language would look like in the year 2015. But these experimentations,
these prototypes, these cardboard mock-ups should not be standardized in
library form, lest these features always remain as merely a library of
fragile hacks. If template meta-programming & reflection are to blossom
fully into a useful style of programming, they deserve full integration
into some post-C++ language itself, instead of second-class citizen
status in a fragile library of hacks in a language which bars their
admittance.
In 1985 would we have wanted C++ to merely have been a bunch of
#defines and libraries in C instead of a post-C language? For those of
us who experimented with #define-macro-with-parameters generators in the
1980s as a crude way of implementing inline functions and for those of
us who experimented with #include mechanisms as a crude way of
implementing parameterized types in the 1980s, one can see how those two
features could have been relegated to a library-of-C-hacks accompanied
by a fragile set of rules governing usage. Indeed, if we had tried hard
enough, I suspect that by function-pointer registration to a
polymorphism library, a crude library-based polymorphism could be
implemented in C for C as well as a library-based inheritance. Did we
push for C-standardization of such hacks for C? No, such a feature-set
is inappropriate to be placed in a library, because these features are
are properties of some language-behavior proper, extrapolating
C-language's control-flow and extrapolating C-language's
data-declaration. That language turned out to be C++.
This put-a-feature-in-the-language versus
put-that-feature-in-a-library debate has a commercial component as well.
This topic of "in whose economic interest is the placement of a
feature in the language or in a library" could explain why certain
trends exist in C++0x and in Boost.
When a feature is placed in the language, compiler vendors must
implement the feature. It is not until a majority of compilers from
multiple vendors on the majority of platforms have implemented that
feature that that feature is deemed "portable". Thus there is a
commercial lag time for the compiler vendors to realize revenue &
profit---a lag time which is in their competitors' control more than it
is in their own, due to this is-it-everywhere-important-yet property of
"portability". Thus compiler vendors have a vested interest in the
status quo of the language, lest the quick-to-market compiler-vendor
perform expensive development this year when that feature is not
deployed in the multi-million/multi-billion line-of-code marketplace
until several years from now.
Conversely, when a feature is placed in a library based on existing
language features, a library vendor can portably implement that feature
across a majority of the existing compilers from multiple vendors on a
majority of platforms. The quick-to-market library vendor performs
development (or better yet enhances a downloaded copy from an open
source code base which was standardized) which can quickly achieve a
competitive advantage in the marketplace over slower library vendors or
library vendors who backed libraries which were not standardized.
Furthermore, compiler vendors need to have implementations quickly of
the newly-standardized libraries. The library vendors who have the
earliest minimum viable product to market again reap monetary reward.
Thus in addition to any other purely-technical or purely-political
factors, there exist nontechnical, economic motivations for features to
be placed in libraries whenever possible instead of within the language
and then have those libraries standardized, creating an economic market
for the library. Is this economic influence best for C++, the
technology (library & language together)? I leave that your own
judgment and to the future.
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: rmaddox@isicns.com (Randy Maddox)
Date: Fri, 16 Aug 2002 12:35:08 GMT Raw View
Ken Thomases <ken@spamnot.codeweavers.com> wrote in message news:<3D589892.3050008@spamnot.codeweavers.com>...
>
> Is it true that providing a constructor causes suppression of
> compiler-supplied destructor? I don't think it is. I just tried this
> in CodeWarrior 8.1:
>
> #include <string>
> #include <vector>
>
> class MyTest
> {
> public:
> MyTest() : m_string("blat"), m_vector(10) { }
> MyTest(const MyTest& in_other) :
> m_string(in_other.m_string), m_vector()
> { m_vector.push_back(m_string); }
>
> private:
> const std::string m_string;
> std::vector<std::string> m_vector;
> };
>
> int main()
> {
> MyTest foo;
> MyTest bar(foo);
> // MyTest gub;
> // gub = foo; // error
> }
>
>
> I figure those constructors have enough meat to be clearly non-trivial.
> The string is const to test suppression of compiler-supplied
> assignment operator. It compiles quite nicely. Now, clearly, for this
> code to be legal the compiler must be getting a destructor from
> somewhere. Right? Neither object's m_string or m_vector are allowed to
> leak, are they?
>
> For kicks, I tried making MyTest privately inherit boost::noncopyable.
> Still compiled, although the compiler error if I uncommented the gub
> lines changed from "using implicit copy assignment for class with const
> or reference member" to "illegal access to private/protected member".
>
> With explicit class, no destructor would be provided. The compiler
> would produce errors for almost any instantiation of the class (except,
> dynamically allocated on the heap and never deleted). What would be the
> value of this? It would remind a programmer who suffered a lapse in
> concentration that their complex class needed a programmer-supplied
> destructor up to the task. Better a compiler error than a
> compiler-supplied destructor which masks the problem.
>
> Ken
>
Speaking of dtors, I would also point out that boost::noncopyable has
a non-virtual dtor, which is pretty unusual for a class intended as a
base class.
Now, I know that the usual idiom is to use private derivation so that
no reference or pointer to a class derived from boost::noncopyable
will be automatically converted to a reference or pointer to its base
class, but there is nothing to enforce this. It's just a convention.
If somehow, somewhere, someone does delete an object of a class
derived from boost::noncopyable using a pointer to its base class, the
correct dtor will not be used, and problems are likely.
Of course, this could easily be fixed by adding a virtual dtor, but I
would presume the reason it was left non-virtual in the first place is
to allow the "empty base class" optimization, which a vtable would
prevent. Oops! Maybe this solution isn't quite as perfect as we
might assume.
So tell me again how boost::noncopyable is better than extending the
use of an existing keyword in a sensible way?
Randy.
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Adam H. Peterson" <ahp6@email.byu.edu>
Date: Fri, 16 Aug 2002 19:43:10 GMT Raw View
> Speaking of dtors, I would also point out that boost::noncopyable has
> a non-virtual dtor, which is pretty unusual for a class intended as a
> base class.
>
> Now, I know that the usual idiom is to use private derivation so that
> no reference or pointer to a class derived from boost::noncopyable
> will be automatically converted to a reference or pointer to its base
> class, but there is nothing to enforce this. It's just a convention.
> If somehow, somewhere, someone does delete an object of a class
> derived from boost::noncopyable using a pointer to its base class, the
> correct dtor will not be used, and problems are likely.
>
> Of course, this could easily be fixed by adding a virtual dtor, but I
> would presume the reason it was left non-virtual in the first place is
> to allow the "empty base class" optimization, which a vtable would
> prevent. Oops! Maybe this solution isn't quite as perfect as we
> might assume.
C++ provides any number of ways to shoot yourself in the foot if you
explicitly try to. I'm all for trying to prevent common errors that might
arise during a normal development cycle, but my brain is doing acrobatics to
try to determine how a scenario would reasonably play out when, 1) someone
derives publicly from noncopyable, and assuming that, 2) any moron would try
to use it as an interface. I don't see the point of protecting a programmer
from something that wouldn't occur to just about anyone actually trying to
solve a problem to do.
>
> So tell me again how boost::noncopyable is better than extending the
> use of an existing keyword in a sensible way?
Okay, here it is again. (I'm talking here about making boost::noncopyable
part of the standard library vs. changing the language to add explicit
class.)
1) We already know it works, and how it works, as we have a proof of concept
in boost. Furthermore, the things in boost's library are already on a track
towards standardization and have a better chance of actually making it into
the next version of the language.
2) It can in most cases be implemented by changing the standard library
alone, so we don't have to make sure we haven't broken the compiler after
changing the grammar since we probably don't need to change the compiler.
3) It doesn't involve overloading a keyword, introducing possible confusion
to a newcomer to the language.
4) It introduces one of the uses of private inheritance, so newcomers to the
language observing this may learn how to use it more effectively. (Note
that it doesn't have to be explained this way. But an astute learner may
simply observe this.)
5) It doesn't introduce yet another way to do something that programmers are
already doing a different way, making skills more portable from one coding
style to another, and preventing the invariable holy wars about how to
suppress these automatic members.
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Gennaro Prota <gennaro_prota@yahoo.com>
Date: Sat, 3 Aug 2002 00:06:20 GMT Raw View
On Thu, 1 Aug 2002 17:55:46 GMT, Ken Thomases
<ken@spamnot.codeweavers.com> wrote:
>What do people think of this: declaring a class as explicit suppresses
>all compiler-supplied functions for that class.
[...]
>Although idiomatic solutions such as boost::noncopyable or simply
>declaring private, never-defined copy constructor and assignment
>operator exist and aren't too taxing, they always seem to end up in the
>"C++ Gotchas" type of book rather than the "Learning the C++ Language"
>books. A direct (and simple) language solution is perhaps more likely
>to be adopted as habit by new C++ programmers.
>
>Well, that's my idea. Be gentle. ;-)
Oddly enough, I've always missed a similar feature that, in a terrific
strain of imagination, I called 'prohibited functions' (be gentle!
:-)) It is basically a way to tell the compiler that a function is
never defined. For instance:
class smart_ptr {
.....
private:
void* operator new (std::size_t); // not impl - new not allowed
};
Note that the operator new function above is not one of those
automatically generated by the implementation. Note also that this
idiom (private and never-defined) has in practice a drawback which is
more evident for example for copy-constructors: accidental uses of the
'prohibited function' from other members of the same class or from
friends are catched only at link time. That's, of course, because the
compiler can't know, until it has seen all the translation units, that
a definition doesn't exists. This also means that the error message
isn't so informative.
class A {
A (const A&); // not implemented: A is non copyable
public:
A (int i) {}
A f() {
return 1; // wouldn't it be nice to have
// an error message here?
}
};
Solutions like boost::noncopyable don't have this limitation, but
still are IMHO something that is only close to what the compiler could
do. Strictly speaking, for instance, this artifact:
// derive from this to inhibit dynamic
// allocation (through new) of derived objects.
//
class banned_from_the_freestore {
private:
void * operator new (std::size_t);
};
class A : banned_from_the_freestore {
};
int main() {
A * p = new A; // error
}
would be completely ineffective if we declared an A::operator new
(std::size_t). Not that this would normally happen but, as I said, it
would be much nicer that such techniques had a better language
support. It also seems to me that this would not require great
changes, except for a little addition to the syntax. I would be
pleased also with a (certainly ugly for someone)
class A {
void * operator new (std::size_t) = false;
};
class A {
void * operator new (std::size_t) = !; // or, equivalently, '= not'.
};
Just a little and I'm happy! See it? :-) In any case, I'm pretty sure
that even if I submitted a serious proposal the benefit wouldn't be
considered worth the effort to change (actually 'extend') the
language.
Genny.
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Ken Thomases <ken@spamnot.codeweavers.com>
Date: Thu, 1 Aug 2002 17:55:46 GMT Raw View
What do people think of this: declaring a class as explicit suppresses
all compiler-supplied functions for that class. This is a response to
all the trouble naive C++ programmers can stumble into by ignoring the
compiler-supplied functions.
explicit class Foo
{
public:
int someValue;
};
Instead of having a compiler-supplied, do-nothing default constructor, a
memberwise copy-constructor, and a memberwise assignment operator, this
class would have none of those. In fact, it wouldn't be possible to
construct a Foo object at all. Obviously, that makes Foo fairly
useless, but does force the implementor to explicitly supply every bit
of functionality s/he really wants.
explicit class Bar
{
public:
Bar(int a, const std::string& b);
private:
int m_a;
std::string m_b;
};
This class would have exactly the one constructor specified and no
assignment operator.
Although idiomatic solutions such as boost::noncopyable or simply
declaring private, never-defined copy constructor and assignment
operator exist and aren't too taxing, they always seem to end up in the
"C++ Gotchas" type of book rather than the "Learning the C++ Language"
books. A direct (and simple) language solution is perhaps more likely
to be adopted as habit by new C++ programmers.
Well, that's my idea. Be gentle. ;-)
---
[ 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://www.jamesd.demon.co.uk/csc/faq.html ]