The article "Using auto_ptr Effectively" by Herb Sutter
<http://www.gotw.ca/publications/using_auto_ptr_effectively.htm>
advocates its usage because the auto_ptr will take care of the
destruction, but somewhere I heard that using std::auto_ptr<T>
where T is an incomplete type at its declaration, which is always
the case, will cause undefined behaviour. Then should I avoid
using std::auto_ptr<pImpl> and use raw pointers for pImpl?
(It's no big deal anyway because the ownership is clear and simple.)
--
Sungbom Kim <musi...@bawi.org>
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
Well if you write the destructor yourself (even if it's empty) and place
it in the source file where the pimpl class is defined, then the pimpl
class in auto_ptr won't be an incomplete type anymore.
But since it is easy to forget this, boost::scoped_ptr is probably a
better candidate. (Since it disallows destruction of incomplete types
for safety.)
Regards,
Dirk Gerrits
Just a note: That page has a header which alludes to that issue and points
out that it's not addressed in the article. The page header says:
This is the original article substantially as first published.
See the book More Exceptional C++ (Addison-Wesley, 2002) for the
most current version of this article. The versions in the book
have been revised and expanded since their initial appearance in
print. The book versions also incorporate corrections, new
material, and conformance to the final ANSI/ISO C++ standard.
In particular, note that the book contains amplifications describing
pitfalls in using auto_ptr as a class member, and how to avoid the
problems.
The last bit is the germane part.
Herb
---
Herb Sutter (www.gotw.ca)
Secretary, ISO WG21/ANSI J16 (C++) standards committee (www.gotw.ca/iso)
Contributing editor, C/C++ Users Journal (www.gotw.ca/cuj)
C++ community program manager, Microsoft (www.gotw.ca/microsoft)
> But since it is easy to forget this, boost::scoped_ptr is probably a
> better candidate. (Since it disallows destruction of incomplete types
> for safety.)
I'm not quite sure what benefit this would actually bring - wouldn't any
user of the class that contains such an "impl" then be unable to destroy
objects of this type unless they can see the complete class "impl"
declaration?
Regards,
Ian Knowles.
If the compiler-generated destructor is used, it should fail to compile
because of this safety check. This forces the author of the class to
write the destructor himself (even if it's empty) in a place where the
pimpl class is no longer an incomplete type (the source file for
example). With auto_ptr you have to do this too, but there will be no
compile-time error if you forget to do so.
That's the way I understand it anyway. Please correct me if I'm wrong.
-Dirk
I guess it is practically okay, but does the standard guarantee that
it works correctly even if Impl class is incomplete at the point of
the declaration of std::auto_ptr<Impl>?
> But since it is easy to forget this, boost::scoped_ptr is probably a
> better candidate. (Since it disallows destruction of incomplete types
> for safety.)
Thanks for the good information.
--
Sungbom Kim <musi...@bawi.org>
boost::scoped_ptr and shared_ptr are better candidates; scoped_ptr
detects attempts to delete incomplete types (this can happen if you
forget an explicit destructor) and shared_ptr "just works," even
without an explicit destructor.
No.
> The article "Using auto_ptr Effectively" by Herb Sutter
> <http://www.gotw.ca/publications/using_auto_ptr_effectively.htm>
> advocates its usage because the auto_ptr will take care of the
> destruction, but somewhere I heard that using std::auto_ptr<T>
> where T is an incomplete type at its declaration, which is always
> the case, will cause undefined behaviour.
It can - if T has a "non-trivial" destructor. (I.e. usually.)
NB Herb Sutter has updated the advice to address this issue in his
more recent material.
> Then should I avoid
> using std::auto_ptr<pImpl> and use raw pointers for pImpl?
> (It's no big deal anyway because the ownership is clear and simple.)
I'd recommend my own arg::grin_ptr<impl> which was designed for this
usage:
http://www.octopull.demon.co.uk/arglib.html
For a discussion of the issues and the design of grin_ptr see:
http://www.octopull.demon.co.uk/arglib/TheGrin.html
PS
I know that some of the ideas have been discussed on boost - but I
don't think that the currently published smart pointers address this
usage.
--
Alan Griffiths <al...@octopull.demon.co.uk> ACCU Chairman
<ch...@accu.org>
http://www.octopull.demon.co.uk/ http://accu.org/
You've got me there. I think so, but I don't know so. Anyone here who does?
- Dirk
No it doesn't. The standard says it is undefined behaviour, which
therefore may or may not compile, and may or may not work as you expect
if it does. #include <standard_description_of_undefined_behaviour>
Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optical Components Ltd
The opinions expressed in this message are not necessarily those of my
employer
>
> If the compiler-generated destructor is used, it should fail to
> compile because of this safety check. This forces the author of the
> class to write the destructor himself (even if it's empty) in a place
> where the pimpl class is no longer an incomplete type (the source file
> for example). With auto_ptr you have to do this too, but there will be
> no compile-time error if you forget to do so.
>
> That's the way I understand it anyway. Please correct me if I'm wrong.
>
This sounds perfectly correct to me, however, if you are going to write
a destructor anyway then how much more difficult is it to put a "delete
p_Impl" in it? If the author understands the "pimple" pattern are they
really that likely to get it wrong without using smart pointers?
It would seem to me to be a little unnecessary to involve smart pointers
just to try and make sure that you don't forget to put "delete p_Impl"
in the destructor. When creating a new class with an "Impl" why not just
start with a source template that provides the Impl construction and
destruction and forget about the smart pointers (which will most likely
force you into adding unnecessary extra #includes and perhaps slow down
the compilation time)?
Regards,
Ian Knowles.
So you're advocating the usage of raw pointers, aren't you?
I had thought about that, and I agree that it is trivially easy
to say "delete pImpl;" in the destructor. No transfer or sharing of
ownership is involved, and even if you use a smart pointer you have
to write a destructor -- though empty -- anyway.
So shall we just get back to raw pointers and say
struct Impl;
Impl* pImpl;
..? :-)
--
Sungbom Kim <musi...@bawi.org>
One advantage of a smart pointer is that you also
get the copy semantic for free. With raw pointers
you have to not to forget the 'delete' in the dtor,
and you have to implement/forbid the copying.
> Sungbom Kim <musi...@bawi.org>
Schobi
--
Spam...@gmx.de is never read
I'm HSchober at gmx dot de
I'd rather think a bit in the direction of policy-based version
of 'move-on-copy'-std::auto_ptr with auto-shared-ownership 'clone-
rhs-ptr-via-its-const-ref-on-copy-and-move-in-result-ptr'-adapter-
extra for our current std containers and algorithms -- sort of
shared_ptr on top of auto_ptr with '_ptr::clone() const' impl
provided by the 'cloning' policy -- deep-copy, or addref/reference
semantic, or whatever... and with 'release policy' responsible for
things like 'delete', or 'delete[]', or 'whatever-placement-delete-
after-manual-dtor(s)-invocation', or 'unref', or 'unlock', or
'close', or whatever... with or without Ex.Specs-protection/
catch(...)-do-something-exception-handling. ;-) ;-) <another
couple of sort-of-kidding smileys>
regards,
alexander.
P.S. 'deref policy' might handle things like 'proxies', 'checking'
and etc... or simply NOTHING for beasts like pure scoped_guards
[including their const version(s) that can neither be copied/moved
nor reset/dismissed; only deleted, and {optionally, prior to the
destruction ;-)} *cloned* -- IFF 'thing<...> clone() const' method
is supported by 'cloning' policy; compile error if NOT supported].
The source template that I use for classes with "pimples" also includes a
private copy constructor and assignment operator and FWIW I think that there
may be a lot more involved than simply having a "copyable" smart pointer
(e.g. should it be a deep copy or can [or should] parts of the Impl be
shared amongst instances?).
If you aren't initially requiring copy semantics then why force yourself to
have to worry about them right from the start?
To my thinking you should consider trying to Keep It Suitably Simple And
Stylishly Spartan (i.e. sometimes KISSing ASS might be better than
unnecessarily working your ass off ;) ).
Regards,
Ian Knowles.