Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

pImpl idiom and std::auto_ptr<>

1 view
Skip to first unread message

Sungbom Kim

unread,
Jun 18, 2002, 11:34:28 AM6/18/02
to
Is it advisable or not to use std::auto_ptr<> for a pImpl idiom?

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! ]

Dirk Gerrits

unread,
Jun 18, 2002, 2:52:14 PM6/18/02
to
Sungbom Kim wrote:
> Is it advisable or not to use std::auto_ptr<> for a pImpl idiom?
>
> 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.)

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

Herb Sutter

unread,
Jun 18, 2002, 9:31:21 PM6/18/02
to
On 18 Jun 2002 11:34:28 -0400, Sungbom Kim <musi...@bawi.org> wrote:
>Is it advisable or not to use std::auto_ptr<> for a pImpl idiom?
>
>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.)

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)

Ian Knowles

unread,
Jun 19, 2002, 5:30:37 AM6/19/02
to
Hi Dirk,

> 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.

Dirk Gerrits

unread,
Jun 19, 2002, 9:17:10 AM6/19/02
to
Ian Knowles wrote:
> Hi Dirk,
>
> > 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?

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

Sungbom Kim

unread,
Jun 19, 2002, 9:21:56 AM6/19/02
to
Dirk Gerrits wrote:
>
> 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.

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>

Peter Dimov

unread,
Jun 19, 2002, 9:22:31 AM6/19/02
to
Sungbom Kim <musi...@bawi.org> wrote in message news:<3D0EBA1B...@bawi.org>...

> Is it advisable or not to use std::auto_ptr<> for a pImpl idiom?
>
> 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.)

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.

Alan Griffiths

unread,
Jun 19, 2002, 11:49:58 AM6/19/02
to
Sungbom Kim <musi...@bawi.org> wrote in message news:<3D0EBA1B...@bawi.org>...
> Is it advisable or not to use std::auto_ptr<> for a pImpl idiom?

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/

Dirk Gerrits

unread,
Jun 19, 2002, 11:53:29 AM6/19/02
to
Sungbom Kim wrote:
> Dirk Gerrits wrote:
>
>>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.
>
>
> 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>?

You've got me there. I think so, but I don't know so. Anyone here who does?

- Dirk

Anthony Williams

unread,
Jun 19, 2002, 6:02:42 PM6/19/02
to
"Sungbom Kim" <musi...@bawi.org> wrote in message
news:3D105870...@bawi.org...

> Dirk Gerrits wrote:
> >
> > 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.
>
> 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>?


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

Ian Knowles

unread,
Jun 20, 2002, 11:16:18 AM6/20/02
to
Dirk Gerrits <di...@chello.nl> wrote in message
news:3D1055FB...@chello.nl...

>
> 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.

Sungbom Kim

unread,
Jun 21, 2002, 7:36:27 AM6/21/02
to
Ian Knowles wrote:
>
> 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)?

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>

Hendrik Schober

unread,
Jun 21, 2002, 12:04:36 PM6/21/02
to
"Sungbom Kim" <musi...@bawi.org> wrote:
> [...]

> > 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?
> [...]

> 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.
> [...]

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

Alexander Terekhov

unread,
Jun 21, 2002, 4:35:30 PM6/21/02
to

Sungbom Kim wrote:
[...]

> So shall we just get back to raw pointers and say
>
> struct Impl;
> Impl* pImpl;
>
> ..? :-)

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].

Ian Knowles

unread,
Jun 22, 2002, 5:41:14 AM6/22/02
to
Hendrik Schober <Spam...@gmx.de> wrote in message
news:aev48q$p7s$1...@news1.transmedia.de...

> "Sungbom Kim" <musi...@bawi.org> wrote:
> > [...]
> > 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.
> > [...]
>
> 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.
>

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.

0 new messages