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

sample auto_ptr template

38 views
Skip to first unread message

Nathan Myers, http://www.cantrip.org/

unread,
Mar 29, 1996, 3:00:00 AM3/29/96
to
Greg Colvin wrote:
> In Santa Cruz we decided to change the auto_ptr copy semantics to
> allow returns of auto_ptr from functions. Following is a simple
> implementation. It (almost) compiles with the latest Edison Design
> Group front end (the template friend declaration choked it).

I hasten to add, in defense of John Spicer's sterling reputation,
that this was not a released EDG front end, but John's pre-alpha
working copy (i.e., only as reliable as other peoples' released
versions :-).

Nathan Myers
n...@cantrip.org
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++...@ncar.ucar.edu ]

Greg Colvin

unread,
Mar 30, 1996, 3:00:00 AM3/30/96
to comp-s...@uunet.uu.net
In Santa Cruz we decided to change the auto_ptr copy semantics to
allow returns of auto_ptr from functions. Following is a simple
implementation. It (almost) compiles with the latest Edison Design
Group front end (the template friend declaration choked it). Note
that on most architectures the owner bit can be overlayed with the
pointer for a smaller footprint, but the following is portable.

template<class X>
class auto_ptr {
mutable bool owner;
X* px;
template<class Y> friend class auto_ptr;
public:
explicit auto_ptr(X* p=0)
: owner(p), px(p) {}
template<class Y>
auto_ptr(const auto_ptr<Y>& r)
: owner(r.owner), px(r.release()) {}
template<class Y>
auto_ptr& operator=(const auto_ptr<Y>& r) {
if ((void*)&r != (void*)this) {
if (owner)
delete px;
owner = r.owner;
px = r.release();
}
return *this;
}
~auto_ptr() { if (owner) delete px; }
X& operator*() const { return *px; }
X* operator->() const { return px; }
X* get() const { return px; }
X* release() const { owner = 0; return px; }
};

Wil Evers

unread,
Apr 3, 1996, 3:00:00 AM4/3/96
to
Hi,

In article <gregorDp...@netcom.com> gre...@netcom.com (Greg Colvin)
writes:

> In Santa Cruz we decided to change the auto_ptr copy semantics to
> allow returns of auto_ptr from functions. Following is a simple
> implementation.
>

> [snip]


>
> template<class X>
> class auto_ptr {
> mutable bool owner;
> X* px;
> template<class Y> friend class auto_ptr;
> public:
> explicit auto_ptr(X* p=0)
> : owner(p), px(p) {}
> template<class Y>
> auto_ptr(const auto_ptr<Y>& r)
> : owner(r.owner), px(r.release()) {}
> template<class Y>
> auto_ptr& operator=(const auto_ptr<Y>& r) {
> if ((void*)&r != (void*)this) {
> if (owner)
> delete px;
> owner = r.owner;
> px = r.release();
> }
> return *this;
> }
> ~auto_ptr() { if (owner) delete px; }
> X& operator*() const { return *px; }
> X* operator->() const { return px; }
> X* get() const { return px; }
> X* release() const { owner = 0; return px; }
> };

If I don't misunderstand the above implementation, it does much more
than just allow auto_ptrs to be returned from functions. It also
allows auto_ptrs to be dereferenced after the ownership of the pointee
has been transferred to another auto_ptr.

Is this intentional? Did the committee explicitly decide to allow
dereferencing of non-owning auto_ptrs? If so, what is the rationale behind
this?

It seems to me that after the ownership has been transferred, the
no-longer-owning auto_ptr points to an object of undetermined ownership
and lifetime. In other words, its behavior is in no way different from
a built-in pointer.

The old (April 95 DWP) definition of auto_ptr at least guaranteed that if an
auto_ptr was pointing at something, it was pointing at a unique and alive
object. Now, we don't even have a way to query if this is the case.

This is a terrible state of affairs, especially when we realize
auto_ptr is the *only* smart pointer we have in the standard library.
In my opinion, it should be renamed to zombie_ptr if it is to keep its
new semantics.

- Wil

Greg Colvin

unread,
Apr 4, 1996, 3:00:00 AM4/4/96
to comp-s...@uunet.uu.net
In article <315D79CD...@cantrip.org> "Nathan Myers, http://www.cantrip.org/" <n...@cantrip.org> writes:

>Greg Colvin wrote:
>> In Santa Cruz we decided to change the auto_ptr copy semantics to
>> allow returns of auto_ptr from functions. Following is a simple
>> implementation. It (almost) compiles with the latest Edison Design
>> Group front end (the template friend declaration choked it).
>
>I hasten to add, in defense of John Spicer's sterling reputation,
>that this was not a released EDG front end, but John's pre-alpha
>working copy (i.e., only as reliable as other peoples' released
>versions :-).

Yes, and I was most pleased to be able (at last) to compile auto_ptr.

Greg Colvin
gre...@netcom.com
>
>Nathan Myers
>n...@cantrip.org


>---
>[ comp.std.c++ is moderated. To submit articles: try just posting with ]
>[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
>[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
>[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
>[ Comments? mailto:std-c++...@ncar.ucar.edu ]
---

[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std...@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++...@ncar.ucar.edu
]

john (j.d.) hickin

unread,
Apr 5, 1996, 3:00:00 AM4/5/96
to
|> This is a terrible state of affairs, especially when we realize
|> auto_ptr is the *only* smart pointer we have in the standard library.
|> In my opinion, it should be renamed to zombie_ptr if it is to keep its
|> new semantics.

It all depends what you want to use an auto_ptr for. I have used classes
like this way before templates or exception handling were added to C++.
The main use was as insurance that certain resources were released on exit
from a block in the face of multiple exit paths from the block.

The January DWP continues to say that auto_ptr provides strict ownership
semantics [20.4.5 Template class auto_ptr]:

2 The auto_ptr provides a semantics of strict ownership. An object may
be safely pointed to by only one auto_ptr, so copying an auto_ptr
copies the pointer and transfers ownership to the destination.

The implementation you have quoted does not contradict the above statement.
The January version of auto_ptr had the owner's stored pointer set to 0 so
that dereferencing under such conditions was not allowed:

X& operator*() const;

Requires:
get() != 0
Returns:
*get()

A simple amendment to the DWP, perhaps already in the works, is all we require:


X& operator*() const;

Requires:
owner == true
Returns:
*get()

With change, dereferencing will, as before, be undefined when ownership is
not held.


--
John Hickin Nortel Technology, Montreal, Quebec
(514) 765-7924 hic...@nortel.ca

Ajay Kamdar

unread,
Apr 5, 1996, 3:00:00 AM4/5/96
to
In article <009A04DA6A83...@ittpub.nl>,

Wil Evers <w...@ittpub.nl> wrote:
>Hi,
>
>In article <gregorDp...@netcom.com> gre...@netcom.com (Greg Colvin)
>writes:
>
>> In Santa Cruz we decided to change the auto_ptr copy semantics to
>> allow returns of auto_ptr from functions. Following is a simple
>> implementation.
>
>This is a terrible state of affairs, especially when we realize
>auto_ptr is the *only* smart pointer we have in the standard library.
>In my opinion, it should be renamed to zombie_ptr if it is to keep its
>new semantics.

I am afraid I agree that this is not going in the right direction.

In a post back in February, Greg Colvin provided the history
and motivation behind the auto_ptr proposal. To reiterate
what he said then, the auto_ptr tries to support the following
idioms:

1. "Resource acquisition is intialization".

This idiom is intended to very considerably simplify the
exception safety of code which allocates some resource,
operates upon this resource, invokes other functions
which could potentially throw an exception, and then
cleans up the resouce before exiting.

This idiom can be supported cleanly and elegantly by
the auto_ptr template, without any change to the
language or the other issues which are causing quite
a discussion.

This idiom was the *only* idiom which auto_ptr was
intended to originally support.


2. Transfer of resource ownership.

This idiom can be used two ways:

2a. The "sink" is called with a resource acquired by
the the caller, and the sink is responsible for
deleting the resource.

2b. The "source" (the caller) is returned a resource
acquired by the callee, and the caller is responsible
for deleting the resource.

This idiom requires the auto_ptr to have copy semantics,
and is the source of all the debate. This idiom was *not*
the original intent of auto_ptr, and was added in response
to some experiences reported by Taligent.


Given this background, it is obvious that trying to support
the Taligent idiom is requiring considerable work, and
it is not clear that a clean solution exists. Greg and others
have tried admirably to come up with solutions, but the extensive
discussions in this newsgroup make it obvious that each of
the solutions leaves many things to be desired. Irrespecitve
of what the Taligent experience has been with this idiom,
the collective experience of the people who have participated
in these discussions (a sum total that far exceeds whatever
Taligent can muster) clearly indicates that the form required
to support the Taligent idiom leaves a lot to be desired.

So why not forget about trying to support the Taligent idiom
in auto_ptr and stay with the original intent of providing a
standardized idiom for exception safety? There is no reason
why the two separate idioms should be married together in
one class. What ever happened to the concept of using the
right tool for the right job? It is perfectly ok
for Taligent to impose a particular idiom on Taligent users
-- the users of the Taligent framework have a choice whether
to use the framework or not. But it is another matter to stuff
a questionable form of the idiom down the throats of every C++
user by making it a part of the standard auto_ptr.

IMHO, it would be a grave mistake for the standardization
comittee to agree upon an auto_ptr which tries to support
the Taligent idiom. Here's what I suggest:

+ The standard auto_ptr should address only the
"resource acquisition is initialization" idiom. It should
not try have any copy semantics.

+ The supporters of the Taligent idiom can, if they feel
strongly about it, propose a taligent_ptr class which
addresses the transfer of resource ownership idiom.
Programmers can then decide whether to use it or not
on its own merit independently of any thing else.

--
Ajay Kamdar | Email: aj...@lehman.com | Standard Disclaimer
Lehman Brothers | Phone: (201) 524-5048 |

Bill Gibbons

unread,
Apr 5, 1996, 3:00:00 AM4/5/96
to
In article <4k0m72$g...@jabba.lehman.com>, aj...@lehman.com (Ajay Kamdar) wrote:

> ... it is obvious that trying to support
> the Taligent idiom [transfer of resource ownership] is requiring


> considerable work, and
> it is not clear that a clean solution exists. Greg and others
> have tried admirably to come up with solutions, but the extensive
> discussions in this newsgroup make it obvious that each of
> the solutions leaves many things to be desired. Irrespecitve
> of what the Taligent experience has been with this idiom,
> the collective experience of the people who have participated
> in these discussions (a sum total that far exceeds whatever
> Taligent can muster) clearly indicates that the form required
> to support the Taligent idiom leaves a lot to be desired.

Well, no. There were more people actively using smart pointers
at Taligent than there have been people discussing them here.
But that isn't really the point...

> So why not forget about trying to support the Taligent idiom
> in auto_ptr and stay with the original intent of providing a
> standardized idiom for exception safety? There is no reason
> why the two separate idioms should be married together in
> one class. What ever happened to the concept of using the
> right tool for the right job? It is perfectly ok
> for Taligent to impose a particular idiom on Taligent users
> -- the users of the Taligent framework have a choice whether
> to use the framework or not. But it is another matter to stuff
> a questionable form of the idiom down the throats of every C++
> user by making it a part of the standard auto_ptr.

Transfer of ownership is not the end goal - the end goal is
to make auto_ptr useful for the "resource acquisition is
initialization" idiom. That is very painful without transfer
of ownership.

In particular, if you want to do the resource acquisition in a
function called by the function which needs to hold the resource,
there is no good exception-safe way to pass the pointer from the
callee to the caller.

You can get close (at some cost in clarity):

extern get_X(auto_ptr<X> &);
void f() {
auto_ptr<X> ptr;
get_X(ptr); // uses reset() to pass the pointer
...
}

but this requires very careful coding in get_X:

void get_X(auto_ptr<X> &ptr) {
X *p = new X;
// WARNING: DO NOT RISK AN EXCEPTION AT THIS POINT
ptr.reset(p);
return;
}

which is now extremely error-prone. Alternatively:

void get_X(auto_ptr<X> &ptr) {
auto_ptr<X> p = new X;
ptr.reset(p.release());
return;
}

but this requires dealing with details of auto_ptr one should
not need to worry about in ordinary code.

With copy semantics:

extern auto_ptr<X> get_X();
void f() {
auto_ptr<X> ptr = get_X();
...
}

auto_ptr<X> get_X() {
return auto_ptr<X>(new X);
}

The easier it is to use auto_ptr, the more often it will be
used when it is needed - and the more often it will be used
correctly.


-- Bill Gibbons (formerly at Taligent)

--
Bill Gibbons
bi...@gibbons.org

Ajay Kamdar

unread,
Apr 6, 1996, 3:00:00 AM4/6/96
to
In article <bill-05049...@bgibbons.vip.best.com>,

Bill Gibbons <bi...@gibbons.org> wrote:
>
>Transfer of ownership is not the end goal - the end goal is
>to make auto_ptr useful for the "resource acquisition is
>initialization" idiom. That is very painful without transfer
>of ownership.
>
>In particular, if you want to do the resource acquisition in a
>function called by the function which needs to hold the resource,
>there is no good exception-safe way to pass the pointer from the
>callee to the caller.
>
>You can get close (at some cost in clarity):
>
[ snip... ]

It is not clear at all that the copy semantics of auto_ptr
are essential for exception-safe transfer of resources.
The same example coded as follows does not use
the copy semantics of auto_ptr:


extern X* get_X(); // returns a resource acquired
// by the callee, to be deleted
// by the caller.

void f() {
auto_ptr<X> ptr = get_X();

// resource allocated by get_X()
...
}

And get_X() is not unnecessarily complicated either:

X* get_X()


{
auto_ptr<X> p = new X;

// ... stuff that could throw an exception

// We got here. Means normal return.
return p.release();
}


What's wrong with this? It doesn't require copy semantics
for auto_ptr. Yet both the caller and the callee
are exception safe and there is no loss of clarity.

Greg Colvin

unread,
Apr 6, 1996, 3:00:00 AM4/6/96
to comp-s...@uunet.uu.net
In article <4jucle$i...@bmtlh10.bnr.ca> "john (j.d.) hickin" <hic...@bnr.ca> writes:
...

>The January DWP continues to say that auto_ptr provides strict ownership
>semantics [20.4.5 Template class auto_ptr]:
>
>2 The auto_ptr provides a semantics of strict ownership. An object may
> be safely pointed to by only one auto_ptr, so copying an auto_ptr
> copies the pointer and transfers ownership to the destination.
>
>The implementation you have quoted does not contradict the above statement.
>The January version of auto_ptr had the owner's stored pointer set to 0 so
>that dereferencing under such conditions was not allowed:
>
>X& operator*() const;
>
> Requires:
> get() != 0
> Returns:
> *get()
>
>A simple amendment to the DWP, perhaps already in the works, is all we require:
>
To my knowledge this is not "already in the works".

>
>X& operator*() const;
>
> Requires:
> owner == true
> Returns:
> *get()
>
>With change, dereferencing will, as before, be undefined when ownership is
>not held.

Please remember that auto_ptr is designed to make sure that pointers are
deleted when exceptions are thrown, not to be sure that already deleted
pointers are not misused. The semantics of auto_ptr are intentionally
"as close as possible" to ordinary pointers: if you use a pointer that is
already deleted the behaviour is undefined, and the same for auto_ptr; if you
use a pointer that is owned by another object (i.e. will be deleted by that
objects destructor) the behaviour is well defined as long as the pointer
remains valid, and the same for auto_ptr; you cannot tell at runtime whether
a pointer is valid, and the same for auto_ptr.

What you can do is design your code so that you know who owns each object when.
The auto_ptr template can help you implement such designs safely. If you
cannot design your code to work with auto_ptr you probably need garbage
collection of some form.

I do not forsee any fundamental changes in the auto_ptr design: its too late
and has taken too much work to get it where it is today. The important issues
are whether it is completely and correctly specified, and whether any
necessary features are missing. In particular:
* Should auto_ptr have an operator-> ? A proposal to add one was nearly
accepted at Santa Cruz, but was withdrawn when the prerequisite extension
failed.
* Should auto_ptr have an operator== ?
* Should any of the auto_ptr functions have exception specifications?
* Many of the requirements can be diagnosed at compile-time but are only
specified to produce undefined behavior at run-time. Should we tighten the
specification? If so, how?

Greg Colvin
gre...@netcom.com
---

David Vandevoorde

unread,
Apr 8, 1996, 3:00:00 AM4/8/96
to
>>>>> "GC" == Greg Colvin <gre...@netcom.com> writes:
[...]
GC> * Should auto_ptr have an operator-> ? A proposal to add one was
nearly accepted at Santa Cruz, but was withdrawn when the
prerequisite extension failed.
[...]

I believe you meant to say `operator->*'.

The `extension' was to add a unary `operator->*' with essentially the
same rules as `operator->()'; with the binary operator->*, it is not
possible to provide a general mechanism equivalent to that of built-in
pointers (you could only overload operator->* for pointer to member
functions with a predetermined limit on the number of parameters).

Daveed

Bill Gibbons

unread,
Apr 8, 1996, 3:00:00 AM4/8/96
to
In article <4k4noe$i...@jabba.lehman.com>, aj...@lehman.com (Ajay Kamdar) wrote:

> ...


> It is not clear at all that the copy semantics of auto_ptr
> are essential for exception-safe transfer of resources.
> The same example coded as follows does not use
> the copy semantics of auto_ptr:
>
>
> extern X* get_X(); // returns a resource acquired
> // by the callee, to be deleted
> // by the caller.
>
> void f() {
> auto_ptr<X> ptr = get_X();
> // resource allocated by get_X()
> ...
> }
>
> And get_X() is not unnecessarily complicated either:
>
> X* get_X()
> {
> auto_ptr<X> p = new X;
>
> // ... stuff that could throw an exception
>
> // We got here. Means normal return.
> return p.release();
> }
>
> What's wrong with this? It doesn't require copy semantics
> for auto_ptr. Yet both the caller and the callee
> are exception safe and there is no loss of clarity.

The problem is that it requires handling the raw pointer.
Any time you transfer ownership by using release() to extract
the raw pointer and then later use the raw pointer to
construct another auto_ptr, there is a window where there is
no exception safety.

Of course you can carefully craft the code to make sure that
no exceptions can be propagated during the window. But there
are two problems:

(1) The maintainers of the code may not be as careful about
exception safety. When everything is handled by
auto_ptr the risk of bugs creeping in is smaller. Such
bugs are very difficult to find by testing.

(2) The interface of get_X does not implicitly document
that the returned pointer refers to an object which
should be automatically deleted on an exception.

--
Bill Gibbons
bi...@gibbons.org
---

J. Kanze

unread,
Apr 9, 1996, 3:00:00 AM4/9/96
to
In article <4k4noe$i...@jabba.lehman.com> aj...@lehman.com (Ajay Kamdar)
writes:

|> In article <bill-05049...@bgibbons.vip.best.com>,
|> Bill Gibbons <bi...@gibbons.org> wrote:
|> >
|> >Transfer of ownership is not the end goal - the end goal is
|> >to make auto_ptr useful for the "resource acquisition is
|> >initialization" idiom. That is very painful without transfer
|> >of ownership.
|> >
|> >In particular, if you want to do the resource acquisition in a
|> >function called by the function which needs to hold the resource,
|> >there is no good exception-safe way to pass the pointer from the
|> >callee to the caller.
|> >
|> >You can get close (at some cost in clarity):
|> >
|> [ snip... ]

|> It is not clear at all that the copy semantics of auto_ptr


|> are essential for exception-safe transfer of resources.
|> The same example coded as follows does not use
|> the copy semantics of auto_ptr:


|> extern X* get_X(); // returns a resource acquired
|> // by the callee, to be deleted
|> // by the caller.

|> void f() {
|> auto_ptr<X> ptr = get_X();
|> // resource allocated by get_X()
|> ...
|> }

|> And get_X() is not unnecessarily complicated either:

|> X* get_X()
|> {
|> auto_ptr<X> p = new X;

|> // ... stuff that could throw an exception

|> // We got here. Means normal return.
|> return p.release();
|> }


|> What's wrong with this? It doesn't require copy semantics
|> for auto_ptr. Yet both the caller and the callee
|> are exception safe and there is no loss of clarity.

As Bill pointed out in a previous incarnation of this thread, `get_X',
as written above is *NOT* exception safe. After the call to p.release,
the compiler will still cause all of the destructors of any local
variables (and any value parameters to the function) to be called. If
any of these destructors throw an exception, you've lost p. For good.

Now, I don't generally think it a good idea to let an exception
propagate out of a destructor. But I don't think that a standard
auto_ptr class should require this sort of additional rule in order to
be useful.

Personally, I would have preferred to see auto_ptr set the pointer to
NULL when ownership was transfered, even though this meant having a
const parameter that wasn't. But I consider the current version
acceptable, and if it is the compromise that is needed to obtain
consensus, I will go along with it. (Although I wouldn't mind an
additional function to indicate whether I was owner or not.)

BTW: although I do not, nor never have, worked for Taligent, my
experience does parallel theirs. So when comparing the number of people
in favor of the idiom, you have to count some of those involved in the
previous discussions, as well as those at Taligent.
--
James Kanze (+33) 88 14 49 00 email: ka...@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung

Ajay Kamdar

unread,
Apr 9, 1996, 3:00:00 AM4/9/96
to
In article <bill-08049...@bgibbons.vip.best.com>,

Bill Gibbons <bi...@gibbons.org> wrote:
>In article <4k4noe$i...@jabba.lehman.com>, aj...@lehman.com (Ajay Kamdar) wrote:
>
[ snip ]

>>
>> What's wrong with this? It doesn't require copy semantics
>> for auto_ptr. Yet both the caller and the callee
>> are exception safe and there is no loss of clarity.
>
>The problem is that it requires handling the raw pointer.
>Any time you transfer ownership by using release() to extract
>the raw pointer and then later use the raw pointer to
>construct another auto_ptr, there is a window where there is
>no exception safety.
>

You didn't say whether the example I gave was exception
safe or not. To reiterate the main points of the example
+ The caller directly initializes an auto_ptr with
the returned value from the calee.
auto_ptr<X> ptr(get_X());

+ The callee releases the pointer from it's own
auto_ptr in it's return statement.

No copy constructors are involved in the return. Hence
there is no possibility of an exception thrown from
a user defined copy constructor. So which window are
you referring to during which there is no exception
safety? I claim there is none.

>Of course you can carefully craft the code to make sure that
>no exceptions can be propagated during the window. But there
>are two problems:

The example I gave is straight forward C++ programming; no
contortions or careful coding are required. The coding
pattern is simple enough that even junior programmers can
be taught to follow it easily.

Many other more useful extensions have been voted down by
the commitee on the grounds that the requested extension
could be implemented by existing mechanisms within the
language, even if those techniques required a fair
amount of work for the programmer. That stance cannot be
more applicable than in the case of the copy semantics
of auto_ptr -- there is simply no need for such semantics
because identical exception safety can be achieved by
a simple coding pattern.


> (1) The maintainers of the code may not be as careful about
> exception safety. When everything is handled by
> auto_ptr the risk of bugs creeping in is smaller. Such
> bugs are very difficult to find by testing.

Let's analyze which code is more difficult to maintain
and difficult to debug -- one using the copy semantics
of auto_ptr or one wihout copy semantics of auto_ptr.

With copy semantics
===================
If the copy ctor of auto_ptr taking a const auto_ptr&
releases its raw pointer by casting away const,
a programmer can accidentaly "lose" the raw pointer from
within an auto_ptr -- even if the programmer was working
with a const auto_ptr. This occurrs because auto_ptr
violates const correctness and releases the raw pointer
from the raw object.

If the copy ctor of the auto_ptr taking a const auto_ptr&
takes ownership of the raw pointer by casting away const
and setting a flag (the latest proposal), the programmer
can end up with a dangling pointer in the original
auto_ptr if the new auto_ptr destructs first and deletes
the raw pointer.

It is possible that even extensive testing may not
uncover such a problem on a less frequently traversed
path in the code. Even if the path is traversed during
testing, an error may or may not be generated when using
the dangling pointer. Hence it is very possible that the
error might escape it to production code.

Without copy semantics of auto_ptr
==================================
By eliminating any surprises due to the standard
auto_ptr violating const correctness and leaving
behind dangling pointers, program correctness is
actually *improved*.

But for the moment assume that even the simple pattern
of using auto_ptr (release() on return in callee,
direct initialization of auto_ptr in caller) is
not followed correctly in some situation. Two major
scenarios are possible:
1. The error happens on a frequently travesed path
in the code, resulting in frequent ommission to
call delete.

In such situations, any of the many good leak
detectors on the market will show the error
during testing. The error will be fixed
before it reached production.

2. The error is rare enough that it occurs only in
production.

By definition, the error is rare. So the application
will lose some resource each time. In practice,
each occurence of a failure to delete a resource is
not disastorous on its own, and the application will
go on.


So which one is better for the C++ programmer? An approach
which can lead to disastorous surprises at run-time
(auto_ptr with copy semantics approach) definitely does
not look the right choice under any stretch of imagination.


> (2) The interface of get_X does not implicitly document
> that the returned pointer refers to an object which
> should be automatically deleted on an exception.

^^^^^^^^^^^^^^^^^^^^^^^

Now we are getting close to what I firmly believe is the
real driving reason behind the push for auto_ptr to
have copy semantics.

Note that in the above quoted text, the reference to
exceptions in "deleted on an exception" is irrelevant.
In this case, the caller must always delete the ptr
allocated by the callee() -- exception or no exception.
Hence the use of auto_ptr in this case has nothing to
do with exception safety. But it has everything to do
with trying to replace documentation accompanying
get_X() saying that the caller must delete the pointer.

In isolation, it is a good goal to replace comments
which prescribe certain behavior with code constructs
which automatically take care of the issue. By
giving copy semantics to auto_ptr, the need to
document transfer of ownership of pointer is sourght
to be eliminated. I firmly believe that *this* is the
real reason behind the copy semantics of auto_ptr, with
exception safety only a peripheral issue at best.
Unfortunately, it is abundantly clear that this attempt
at replacing documentation by giving auto_ptr copy
semantics has pretty high costs.

I strongly urge those who can do something about this
(those on the committee) to step back and separate
the wheat from the chaff. Don't make auto_ptr harder
to use for *all* C++ programmers by allowing it to
have copy semantics. Make a separate class
(taligent_ptr) which has the copy semantics for
those who *choose* to use it, rather than forcing
everyone to program with an unfortunate choice.


--
Ajay Kamdar | Email: aj...@lehman.com | Standard Disclaimer
Lehman Brothers | Phone: (201) 524-5048 |
---

Wil Evers

unread,
Apr 10, 1996, 3:00:00 AM4/10/96
to
In article <gregorD...@netcom.com> gre...@netcom.com (Greg
Colvin) writes:

> Please remember that auto_ptr is designed to make sure that pointers
> are deleted when exceptions are thrown, not to be sure that already
> deleted pointers are not misused. The semantics of auto_ptr are
> intentionally "as close as possible" to ordinary pointers: if you
> use a pointer that is already deleted the behaviour is undefined,
> and the same for auto_ptr; if you use a pointer that is owned by
> another object (i.e. will be deleted by that objects destructor) the
> behaviour is well defined as long as the pointer remains valid, and
> the same for auto_ptr; you cannot tell at runtime whether a pointer
> is valid, and the same for auto_ptr.

My original question was "Did the committee explicitly decide to allow


dereferencing of non-owning auto_ptrs? If so, what is the rationale

behind this?" It seems to me Greg's answer is "Yes, because that's
what ordinary pointers do." I cannot understand this. Why allow a
dangerous operation just because ordinary pointers do not prohibit it?

Please note:

1. The previous (April '95 DWP) incarnation of auto_ptr did not forbid
to have a second, non-owning, pointer to the owned object. However,
in order to get one, we had to explicitly call the get() member
function, which returns an ordinary pointer. In my opinion, requiring
the user to go through all this trouble was a reasonable safeguard
against accessing released memory and unintended aliasing. In the new
incarnation, there are no such guarantees: an auto_ptr silently
changes into a zombie pointer as a side effect of a copy operation.

2. We all have to pay the price for the committee's decision. The
new implementation is about twice as complicated - up to the point
where almost no existing compiler can handle it - and half as
efficient. Furthermore, dropping a guarantee always breaks existing
code.

What I definitely do not understand is why the new auto_ptr template
doesn't even allow us to query if it is actually owning the object
pointed to.

> What you can do is design your code so that you know who owns each
> object when. The auto_ptr template can help you implement such
> designs safely. If you cannot design your code to work with
> auto_ptr you probably need garbage collection of some form.

auto_ptr may have been designed to provide only limited functionality,
but since it is the only heap object management facility in the
standard, it will be used in many different contexts. Therefore, I
think it is quite resonable to ask how easy it is to abuse it. What I
dislike about the new auto_ptr incarnation is that it is even easier
to abuse than the old one.

- Wil
---

john (j.d.) hickin

unread,
Apr 10, 1996, 3:00:00 AM4/10/96
to
|> What you can do is design your code so that you know who owns each object when.
|> The auto_ptr template can help you implement such designs safely. If you
|> cannot design your code to work with auto_ptr you probably need garbage
|> collection of some form.

I have no problem with this approach which is, in fact, forced on one by the
sample implementation, because it is no longer possible to determine ownership
through a member function.

--
John Hickin Nortel Technology, Montreal, Quebec
(514) 765-7924 hic...@nortel.ca

[ comp.std.c++ is moderated. To submit articles: try just posting with ]

J. Kanze

unread,
Apr 10, 1996, 3:00:00 AM4/10/96
to
In article <4kcr2d$p...@jabba.lehman.com> aj...@lehman.com (Ajay Kamdar)
writes:

|> In article <bill-08049...@bgibbons.vip.best.com>,
|> Bill Gibbons <bi...@gibbons.org> wrote:
|> >In article <4k4noe$i...@jabba.lehman.com>, aj...@lehman.com (Ajay Kamdar) wrote:
|> >
|> [ snip ]
|> >>
|> >> What's wrong with this? It doesn't require copy semantics
|> >> for auto_ptr. Yet both the caller and the callee
|> >> are exception safe and there is no loss of clarity.
|> >
|> >The problem is that it requires handling the raw pointer.
|> >Any time you transfer ownership by using release() to extract
|> >the raw pointer and then later use the raw pointer to
|> >construct another auto_ptr, there is a window where there is
|> >no exception safety.
|> >

|> You didn't say whether the example I gave was exception
|> safe or not.

But I did. It's not.

|> To reiterate the main points of the example
|> + The caller directly initializes an auto_ptr with
|> the returned value from the calee.
|> auto_ptr<X> ptr(get_X());

|> + The callee releases the pointer from it's own
|> auto_ptr in it's return statement.

|> No copy constructors are involved in the return. Hence
|> there is no possibility of an exception thrown from
|> a user defined copy constructor. So which window are
|> you referring to during which there is no exception
|> safety? I claim there is none.

The destructors of any local variables in get_X.

|> >Of course you can carefully craft the code to make sure that
|> >no exceptions can be propagated during the window. But there
|> >are two problems:

|> The example I gave is straight forward C++ programming; no
|> contortions or careful coding are required. The coding
|> pattern is simple enough that even junior programmers can
|> be taught to follow it easily.

The only real solution I can think of to be 100% exception safe would be
to write get_X as follows:

T*
get_X()
{
auto_ptr< T > localTmp ;
{
// All of the work here, including assigning the actual
// pointer to localTmp, and above all, all local variables
// except localTmp here.
}
return localTmp.release() ;
}

While the pattern isn't that complicated, it is certainly not what we
are used to, and is likely to be forgotten from time to time.

|> Many other more useful extensions have been voted down by
|> the commitee on the grounds that the requested extension
|> could be implemented by existing mechanisms within the
|> language, even if those techniques required a fair
|> amount of work for the programmer. That stance cannot be
|> more applicable than in the case of the copy semantics
|> of auto_ptr -- there is simply no need for such semantics
|> because identical exception safety can be achieved by
|> a simple coding pattern.

I imagine that the committee is more tolerant with regards to extensions
which are purely library issues. Library issues are almost guaranteed
by their very nature not to have a surprise side effect in other parts
of the language.

I think the question here is one of patterns. The auto_ptr is designed
to implement simply certain basic, frequently occuring patterns. If it
is used for other things, it is unsafe.

Because its only legitimate use *is* these frequently occuring patterns,
any other use is easily detected by code review. The alternative, using
raw pointers, is more dangerous, because raw pointers have so many uses;
the error is not immediately apparent.

In short, you are suggesting that memory leaks are OK, as long as they
don't occur too often. This isn't the case for my applications.

|> > (2) The interface of get_X does not implicitly document
|> > that the returned pointer refers to an object which
|> > should be automatically deleted on an exception.
|> ^^^^^^^^^^^^^^^^^^^^^^^

|> Now we are getting close to what I firmly believe is the
|> real driving reason behind the push for auto_ptr to
|> have copy semantics.

|> Note that in the above quoted text, the reference to
|> exceptions in "deleted on an exception" is irrelevant.
|> In this case, the caller must always delete the ptr
|> allocated by the callee() -- exception or no exception.
|> Hence the use of auto_ptr in this case has nothing to
|> do with exception safety. But it has everything to do
|> with trying to replace documentation accompanying
|> get_X() saying that the caller must delete the pointer.

No. The caller cannot possibly delete the pointer, since the pointer is
never assigned at the caller side if an exception occurs. The caller
never even sees the pointer.

The whole point of the copy semantics is that there is a period of time
after the evaluation of the return value in the return statement when
neither the callee nor the caller have access to the pointer. Using a
temporary class object means, however, that this object does have
access, and can delete the object if an exception is thrown. The
alternative is somehow to ensure that no exception can be thrown. This
is not always trivial.

|> In isolation, it is a good goal to replace comments
|> which prescribe certain behavior with code constructs
|> which automatically take care of the issue. By
|> giving copy semantics to auto_ptr, the need to
|> document transfer of ownership of pointer is sourght
|> to be eliminated. I firmly believe that *this* is the
|> real reason behind the copy semantics of auto_ptr, with
|> exception safety only a peripheral issue at best.
|> Unfortunately, it is abundantly clear that this attempt
|> at replacing documentation by giving auto_ptr copy
|> semantics has pretty high costs.

There are two separate problems: the unexpected semantics of assignment,
and the exception safety. Because of the way the language is defined,
we can only define auto_ptr to handle one correctly; the other must be
left to comments. (I think that we more or less agree up until this
point.) The question is: which one?

IMHO, requiring the programmer to handle the exception safety is
non-intuitive, difficult, and error prone. While I agree that requiring
the programmer to handle the strange copy semantics is non-intuitive, it
is relatively easy to check. In all *valid* uses of auto_ptr, an
auto_ptr which is copied should immediately go out of scope. This is
trivially true in the case of source functions, like get_X. The only
point which requires a little bit of attention is when copying to a
sink; I would generally try and arrange my code so that the call to the
sinking function is the last thing in the block in which the auto_ptr
was declared, but I'm not certain that this is always possible or
natural. (In practice, until now, it has always been the most natural
way of writing the code anyway.)

Any attempts to assign between two declared auto_ptr's, or to initialize
an auto_ptr with another declared auto_ptr, should be caught by code
review.

|> I strongly urge those who can do something about this
|> (those on the committee) to step back and separate
|> the wheat from the chaff. Don't make auto_ptr harder
|> to use for *all* C++ programmers by allowing it to
|> have copy semantics. Make a separate class
|> (taligent_ptr) which has the copy semantics for
|> those who *choose* to use it, rather than forcing
|> everyone to program with an unfortunate choice.

I believe that John Skaller had a proposal with something like six
different pointer types. The committee found this a little too
complicated for its likings (I would agree), and settled on defining two
(or maybe three).

For various reasons, it was unable to find a definition of counted_ptr
which would obtain a concensus. In some ways, this is regrettable, but
if you look at the implementations of this class in Barton and Nackman,
on one hand, and Meyers II on the other, you can see that in fact, there
are contradictory goals to be met. I have no problem understanding why
no concensus could be reached.

In the case of auto_ptr, those (like Bill Gibbons) with extensive
practical experience actually using such a pointer indicated that to be
useful, it needed copy semantics. (I might add that this corresponds
exactly to my experience.) Without copy semantics, it simply wouldn't
be used in most cases. (Or programmers would resort to tricks such as
returning the pointer as a raw pointer, with the resulting loss of
exception safety.)


--
James Kanze (+33) 88 14 49 00 email: ka...@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung

Greg Colvin

unread,
Apr 11, 1996, 3:00:00 AM4/11/96
to
In article <009A0A5CE115...@ittpub.nl> "Wil Evers" <w...@ittpub.nl>
writes:

Pre April, an auto_ptr silently changed into a null pointer after
copying, except that trying to copy it was ill-formed. Post April
copying is allowed. Derereferencing a null pointer gives undefined
behavior, as does dereferencing a pointer to a deleted object, so I
don't see such a big difference. Given
void f(auto_ptr<T>);
auto_ptr<T> p(px);
then before April we had
f(p); // unintentionally ill-formed
p->whatever(); // undefined behavior
and after April we have
f(p); // well-formed
p->whatever(); // possibly undefined behavior

It is not hard to create a version of auto_ptr that throws an exception
if the "zombie pointer" is dereferenced, at some cost in performance,
and I hope vendors will provide such versions for debugging at least.
If an implementation provides a garbage collector (which is hard) then
providing a safer auto_ptr becomes fairly easy and cheap. Vendors are
always allowed to define undefined behavior to something more useful.

>2. We all have to pay the price for the committee's decision. The
>new implementation is about twice as complicated - up to the point
>where almost no existing compiler can handle it - and half as
>efficient. Furthermore, dropping a guarantee always breaks existing
>code.

Actually, no compiler has ever been able to compile any version of
auto_ptr, since they all have used member templates.

My implementation of auto_ptr is not, IMHO, significantly more
complicated that before (one more member and a few tests, no big
deal). The complication has always been in the member templates.

>
>What I definitely do not understand is why the new auto_ptr template
>doesn't even allow us to query if it is actually owning the object
>pointed to.
>

This was a hard call, and I'm open to suggestions. Adding a mutable
member to a class is never pretty, but making the member visible in any
way is ugly: I don't like for a const argument to change its value,
and I think of the value of an object as being whatever its public
interface reveals. Thus, I find "mutable bool owner" just barely
tolerable, and "bool is_owner() { return owner;} " quite distasteful.

As a practical matter, I can imagine implementations of auto_ptr that
do not store the ownership in the auto_ptr, but perhaps in the bowels
of an OS provided garbage collection system, such that is_owner() might
be very hard to implement efficiently.

Also, I found it very hard to contrive examples where is_owner() would
actually be useful. I think most such examples would involve passing a
reference to an auto_ptr to a function that may or may not then take
ownership. In that case, the callee can always zero out the auto_ptr
argument itself. An alternative idiom is:
template<typename T> auto_ptr<T> source_sink(auto_ptr<T>);
...
p = source_sink(p);
if (&*p)
...

>> What you can do is design your code so that you know who owns each
>> object when. The auto_ptr template can help you implement such
>> designs safely. If you cannot design your code to work with
>> auto_ptr you probably need garbage collection of some form.
>

>auto_ptr may have been designed to provide only limited functionality,
>but since it is the only heap object management facility in the
>standard, it will be used in many different contexts. Therefore, I
>think it is quite resonable to ask how easy it is to abuse it. What I
>dislike about the new auto_ptr incarnation is that it is even easier
>to abuse

I still think that being able to tell who owns an auto_ptr will lead even
more "abuse", since if need to ask you will inevitably forget to ask, and
crash as a result. And if you need to know, then your design is probably
not appropriate for an auto_ptr<> anyway. Don't ask, don't tell.

If anyone can think of examples where an is_owner() is really required
please let me know. A workable fudge might be a protected is_owner(),
so that you have to work at abusing it.

Greg Colvin
gre...@netcom.com
---

Greg Colvin

unread,
Apr 11, 1996, 3:00:00 AM4/11/96
to comp-s...@uunet.uu.net
In article <gregorDp...@netcom.com> gre...@netcom.com (Greg Colvin) writes:
>
>Pre April, an auto_ptr silently changed into a null pointer after
>copying, except that trying to copy it was ill-formed. Post April
>copying is allowed. Derereferencing a null pointer gives undefined
>behavior, as does dereferencing a pointer to a deleted object, so I
>don't see such a big difference. Given
> void f(auto_ptr<T>);
> auto_ptr<T> p(px);
>then before April we had
> f(p); // unintentionally ill-formed
> p->whatever(); // undefined behavior
>and after April we have
> f(p); // well-formed
> p->whatever(); // possibly undefined behavior

Silly me. Of course that should be:
... Given
void f(auto_ptr<T>);
auto_ptr<T> g();
auto_ptr<T> p;


then before April we had

p = g(); // unintentionally ill-formed
f(p);

p->whatever(); // undefined behavior
and after April we have

p = g(); // well formed
f(p);


p->whatever(); // possibly undefined behavior

I hope I got it right this time :-)

Igor Boukanov

unread,
Apr 11, 1996, 3:00:00 AM4/11/96
to
Greg Colvin (gre...@netcom.com) wrote:
> This was a hard call, and I'm open to suggestions. Adding a mutable
> member to a class is never pretty, but making the member visible in any
> way is ugly: I don't like for a const argument to change its value,
> and I think of the value of an object as being whatever its public
> interface reveals.

But why in this case instead of adding mutable member just change
auto_ptr<T>(const auto_ptr<T>&) to auto_ptr<T>(auto_ptr<T>&)
and
auto_ptr<T>& operator=(const auto_ptr<T>&) to
auto_ptr<T>& operator=(auto_ptr<T>&)

This will explicitly reflect the semantic of auto_ptr and if somebody really
want to change the state of const object, they can explicitly wright
about this:
auto_ptr<someType> autoPtr(const_cast<auto_ptr<someType>&>(autoPtrConst));


--
Regards, Igor Boukanov.
igor.b...@fi.uib.no
http://www.fi.uib.no/~boukanov/

Ajay Kamdar

unread,
Apr 11, 1996, 3:00:00 AM4/11/96
to
In article <KANZE.96A...@gabi.gabi-soft.fr>,
J. Kanze <ka...@gabi-soft.fr> wrote:
>In article <4k4noe$i...@jabba.lehman.com> aj...@lehman.com (Ajay Kamdar)
>writes:
>
>|> In article <bill-05049...@bgibbons.vip.best.com>,
>|> What's wrong with this? It doesn't require copy semantics
>|> for auto_ptr. Yet both the caller and the callee
>|> are exception safe and there is no loss of clarity.
>
>As Bill pointed out in a previous incarnation of this thread, `get_X',
>as written above is *NOT* exception safe. After the call to p.release,
>the compiler will still cause all of the destructors of any local
>variables (and any value parameters to the function) to be called. If
>any of these destructors throw an exception, you've lost p. For good.
>
>Now, I don't generally think it a good idea to let an exception
>propagate out of a destructor. But I don't think that a standard
>auto_ptr class should require this sort of additional rule in order to
>be useful.


I don't think a standard auto_ptr class should require additional
rules on the use of const objects (auto_ptrs) in order to be
useful.

The currently proposed auto_ptr semantics require additional
rules to be followed by the programmer regarding how the
auto_ptr is used to ensure protection against dangling pointers.
That burden is more onerous by far than any benefits gained by
trying to support the questionable practice of allowing exceptions
to propagate out of destructors.

The following example demonstrates why allowing exceptions to
propogate out of destructors is more trouble than it is worth:

auto_ptr<X> get_X()


{
auto_ptr<X> p = new X;

auto_ptr<X> temp = new X;
BadIdea b1; // throws an exception in dtor
BadIdea b2; // throws an exception in dtor

// ... stuff

return p;
}

When b2 is destructed, it throws an exception. So what happens
next?

Does the run time system try to continue to destruct b1, temp,
and p? If it does, b1's destructor is also going to thow an
exception. If I interpret 15.5.1 in theApril '95 CD correctly
(I don't have access to any later drafts), terminate() is called
because of the exception propagating out of b1's destructor.
In this case, the destructors of the auto_ptrs would never fire,
making the use of auto_ptrs rather moot.

If on the other hand the run time system abandons executing
the other destuctors in get_X() after b2's destructor has
thrown an exception, the destructors of b1, temp, and p would
never be executed. This would in turn mean that the resource
held by temp will never be deleted, making the use of auto_ptr
rather moot.

To recap, the only exception handling related situation in which
the copy semantics of auto_ptr can concievably help are related
to exceptions propagating out of destructors. But a program
appears to be either doomed to terminate or to lose resources
in such situations, making the practice of allowing exceptions
to propagate out of destructors to be an extremely poor one.

Now I don't think it is a good idea to make the use of auto_ptrs
difficult for normal programming by allowing the possibility
of dangling pointers and such other nasty things to support
the questionable practice of exceptions propagating out of
destructors. Do you?

The only situation in which the copy semantics of auto_ptr
do have useful value is in enforcing that resources transferred
from the caller to callee (or vice versa) are eventually deleted.
But this idiom has got nothing to do with exception handling.
And that is why I have been suggesting the following:

+ The job of auto_ptr should be to assist in exception handling
situations. An auto_ptr without copy semantics serves just
fine in all normal exception handling situations. So remove
the copy semantics from auto_ptr and make it a much safer
class for programmers to use by removing the possibility of
dangling pointers.

+ Create a separate taligent_ptr class to assist in situations
in which resource ownership is being transferred. This class
could open up the possibility of dangling pointers, but the
programmer would have the choice of using it or not.

The current auto_ptr class is trying to solve loosely related, but
fundamentally different, problems at the same time. Breaking up
the unnecessary coupling of the functionality can only help to
make auto_ptr safer to use.

Note: Greg Colvin's article in February mentioned that the initial
impetus for the copy semantics for the standard auto_ptr came
from experiences reported from Taligent. Obviously, Taligent's
experiences are not unique. Other have reported that they have
used the idiom, and so have I. But it is nice to be able to
give an unambigious name to an idiom to make it easier to talk
about, and "Taligent idiom" and "taligent_ptr" just happen to
be convenient names for me to use. Nothing more should be
inferred from the use of the Taligent name.

--
Ajay Kamdar | Email: aj...@lehman.com | Standard Disclaimer
Lehman Brothers | Phone: (201) 524-5048 |

Fergus Henderson

unread,
Apr 12, 1996, 3:00:00 AM4/12/96
to
aj...@lehman.com (Ajay Kamdar) writes:

>The following example demonstrates why allowing exceptions to
>propogate out of destructors is more trouble than it is worth:
>
> auto_ptr<X> get_X()
> {
> auto_ptr<X> p = new X;
> auto_ptr<X> temp = new X;
> BadIdea b1; // throws an exception in dtor
> BadIdea b2; // throws an exception in dtor
>
> // ... stuff
>
> return p;
> }
>
>When b2 is destructed, it throws an exception. So what happens
>next?
>
>Does the run time system try to continue to destruct b1, temp,
>and p?

Yes.

>If it does, b1's destructor is also going to thow an
>exception. If I interpret 15.5.1 in theApril '95 CD correctly
>(I don't have access to any later drafts), terminate() is called
>because of the exception propagating out of b1's destructor.

That's right. I'm pretty sure this hasn't changed in the more recent drafts.

>If on the other hand the run time system abandons executing
>the other destuctors in get_X() after b2's destructor has
>thrown an exception,

Such an implementation would not be conforming.

(Incidentally, I agree quite strongly with the arguments voiced by
Ajay Kamdar in this thread.)

--
Fergus Henderson <f...@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger f...@128.250.37.3 | -- the last words of T. S. Garp.
---

Fergus Henderson

unread,
Apr 12, 1996, 3:00:00 AM4/12/96
to
aj...@lehman.com (Ajay Kamdar) writes:

>The following example demonstrates why allowing exceptions to
>propogate out of destructors is more trouble than it is worth:
>
> auto_ptr<X> get_X()
> {
> auto_ptr<X> p = new X;
> auto_ptr<X> temp = new X;
> BadIdea b1; // throws an exception in dtor
> BadIdea b2; // throws an exception in dtor
>
> // ... stuff
>
> return p;
> }
>
>When b2 is destructed, it throws an exception. So what happens
>next?
>
>Does the run time system try to continue to destruct b1, temp,
>and p?

Yes.

>If it does, b1's destructor is also going to thow an
>exception. If I interpret 15.5.1 in theApril '95 CD correctly
>(I don't have access to any later drafts), terminate() is called
>because of the exception propagating out of b1's destructor.

That's right. I'm pretty sure this hasn't changed in the more recent drafts.

>If on the other hand the run time system abandons executing


>the other destuctors in get_X() after b2's destructor has
>thrown an exception,

Such an implementation would not be conforming.

(Incidentally, I agree quite strongly with the arguments voiced by
Ajay Kamdar in this thread.)

--
Fergus Henderson <f...@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger f...@128.250.37.3 | -- the last words of T. S. Garp.
---

J. Kanze

unread,
Apr 12, 1996, 3:00:00 AM4/12/96
to
In article <4kjcvb$g...@ugress.uib.no> bouk...@sentef1.fi.uib.no (Igor
Boukanov) writes:

|> Greg Colvin (gre...@netcom.com) wrote:
|> > This was a hard call, and I'm open to suggestions. Adding a mutable
|> > member to a class is never pretty, but making the member visible in any
|> > way is ugly: I don't like for a const argument to change its value,
|> > and I think of the value of an object as being whatever its public
|> > interface reveals.

|> But why in this case instead of adding mutable member just change


|> auto_ptr<T>(const auto_ptr<T>&) to auto_ptr<T>(auto_ptr<T>&)
|> and
|> auto_ptr<T>& operator=(const auto_ptr<T>&) to
|> auto_ptr<T>& operator=(auto_ptr<T>&)

|> This will explicitly reflect the semantic of auto_ptr and if somebody really
|> want to change the state of const object, they can explicitly wright
|> about this:
|> auto_ptr<someType> autoPtr(const_cast<auto_ptr<someType>&>(autoPtrConst));

We've been through all this before. That was the original version.
Regretfully, makes it impossible to return an auto_ptr from a function.
And one of the more frequent uses of auto_ptr involves returning them
from functions.


--
James Kanze (+33) 88 14 49 00 email: ka...@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung

Lars Farm

unread,
Apr 12, 1996, 3:00:00 AM4/12/96
to
In article <KANZE.96A...@gabi.gabi-soft.fr>,
ka...@gabi-soft.fr (J. Kanze) wrote:

>I believe that John Skaller had a proposal with something like six
>different pointer types. The committee found this a little too

He said a while ago that he proposed two classes(*). (1) auto_ptr for
lifetime control within a block (no copy/assign) and (2) a ref counted
class for shared objects. There is a need for both but only one was
accepted and that is the real problem.

auto_ptr<> is slowly being mutated into a mixture of the two classes. It
has moved away from its original goal and is becoming a cheap shared_ptr<>.
This requires very strange and disturbing use of op=/copy.

void f( auto_ptr<X> x ) { ...will delete x }

// promise: x const, x will _not_ change, x will _not_ become invalid
void g( const auto_ptr<X>&x ) {
// ... x ok
f(x);
// ... oops
}
void h() {
auto_ptr<X> p( new X );
// p valid
g(x);
// p bad. Undetected by the compiler because the standard
// library class auto_ptr subverted the C++ type system
}

IMHO the only reasonable solution is to have two classes. If the committee
only accepts one then users will have to write the other. That's ok, as
long as it is obvious that auto_ptr isn't a general purpose smart_ptr. With
the current weird auto_ptr copy/op= perhaps users will have to write both
the original and the ref counted class on their own. Or worse, they will
actually use auto_ptr as if it was the rejected ref_counted ptr. This is a
reasonable assumption because auto_ptr is the only standard smart ptr and
users should be allowed to assume it is safe. It would be safe with private
op=/copy as the original.

When designing a class for mass consumption it should not only support the
intended idioms. It should also prevent missuse in common situations. The
original does that. The current auto_ptr doesn't.

Please reconsider John Max Skallers original proposal.

(*) he has also mentioned other smart pointers here. holding arrays -
block/ref-counted. copying pointers and cloning pointers using varying
implementation techniques but AFAIK they were never proposed as standard
classes.

--
Lars Farm, lars...@nts.mh.se

Ajay Kamdar

unread,
Apr 12, 1996, 3:00:00 AM4/12/96
to
In article <KANZE.96A...@gabi.gabi-soft.fr>,
J. Kanze <ka...@gabi-soft.fr> wrote:
>In article <4kcr2d$p...@jabba.lehman.com> aj...@lehman.com (Ajay Kamdar)
>writes:
>
>|> You didn't say whether the example I gave was exception
>|> safe or not.
>
>But I did. It's not.
>
>|> To reiterate the main points of the example
>|> + The caller directly initializes an auto_ptr with
>|> the returned value from the calee.
>|> auto_ptr<X> ptr(get_X());
>
>|> + The callee releases the pointer from it's own
>|> auto_ptr in it's return statement.
>
>|> No copy constructors are involved in the return. Hence
>|> there is no possibility of an exception thrown from
>|> a user defined copy constructor. So which window are
>|> you referring to during which there is no exception
>|> safety? I claim there is none.
>
>The destructors of any local variables in get_X.

Yes, you are right that the destructors of local variables in
get_X() could propagate exceptions. I missed that in my initial
analysis. However, in a previous article I believe I have shown
clearly that propagating exceptions out of destructors is an
extremely poor practice. Depending upon whether the destruction
of remaining stack variables in get_X() is attempted if one of
the statck variables throws an exception, the program will either
terminate or will likely leak memory. I think it would be a
dubious choice to make auto_ptr less safe to use by making it have
copy semantics to support such off beat no-win cases.

[snip]


>
>|> So which one is better for the C++ programmer? An approach
>|> which can lead to disastorous surprises at run-time
>|> (auto_ptr with copy semantics approach) definitely does
>|> not look the right choice under any stretch of imagination.
>
>In short, you are suggesting that memory leaks are OK, as long as they
>don't occur too often. This isn't the case for my applications.


Applications which cannot tolerate even occasional memory leaks
when exceptions propagate through destructors (if they are
lucky to live past those exceptions) should go through sufficient
testing to find all such occurences. Enough memory leak detection
tools exist on the market to make this possible. The onus
of finding those leaks is on those applications. Alternatively
they could use garbage collection. Given that even an auto_ptr
having copy semantics does not really solve the problem with
exceptions emnating from destructors, I have a hard time buying
into warping the auto_ptr design and making it unsafe for
everyone to support such applications.

Moreover, if the unsafe copy semantics are moved out of auto_ptr
into taligent_ptr, applications which are willing to accept
the unsafe semantics and the lack of a complete solution inspite
of sacrificing safety can always use the taligent_ptr. But it
would be a *choice* that is not imposed upon everyone using the
standard auto_ptr class.

--
Ajay Kamdar | Email: aj...@lehman.com | Standard Disclaimer
Lehman Brothers | Phone: (201) 524-5048 |

---

Nathan Myers <ncm@cantrip.org>

unread,
Apr 13, 1996, 3:00:00 AM4/13/96
to
Greg Colvin wrote:

> In article <009A0A5CE115...@ittpub.nl> "Wil Evers" <w...@ittpub.nl>:


> >What I definitely do not understand is why the new auto_ptr template
> >doesn't even allow us to query if it is actually owning the object
> >pointed to.

> I found it very hard to contrive examples where is_owner() would
> actually be useful.

I agree with Greg here: any code that is intended to execute
differently, depending on the value returned by putative member
auto_ptr<>::is_owner(), is just bad code.

I can imagine:

auto_ptr<T> p1;
auto_ptr<T> p2 = new T;
if (...) {
p1 = p2;
}
// what to do here?

The answer is: it's your responsibility to keep track of ownership
of pointers; if you can't do it manually, then automate it with
reference counting or something. That's not what auto_ptr<> is for;
its purpose is to make sure that the value "new T" gets destroyed.
It does that job perfectly; don't ask it to do your job too.

Nathan Myers
n...@cantrip.org http://www.cantrip.org/

Greg Colvin

unread,
Apr 14, 1996, 3:00:00 AM4/14/96
to comp-s...@uunet.uu.net
In article <AD940979...@sleipner.nts.mh.se> lars...@nts.mh.se

(Lars Farm) writes:
>In article <KANZE.96A...@gabi.gabi-soft.fr>,
>ka...@gabi-soft.fr (J. Kanze) wrote:
>
>>I believe that John Skaller had a proposal with something like six
>>different pointer types. The committee found this a little too
>
>He said a while ago that he proposed two classes(*). (1) auto_ptr for
>lifetime control within a block (no copy/assign) and (2) a ref counted
>class for shared objects. There is a need for both but only one was
>accepted and that is the real problem.
>
>
>auto_ptr<> is slowly being mutated into a mixture of the two classes. It
>has moved away from its original goal and is becoming a cheap shared_ptr<>.
>This requires very strange and disturbing use of op=/copy.

Yes, auto_ptr has evolved. I don't find that strange or disturbing.

>
>void f( auto_ptr<X> x ) { ...will delete x }
>
> // promise: x const, x will _not_ change, x will _not_ become invalid

It is indeed a shame that all this promise cannot be kept for auto_ptr.
If someone can work out a change to the base language to allow for non-const
copy operations, make sure that it doesn't break anything else, work out
exact wording for the working paper, and convince the committee to accept
the change, then I would gladly propose going back to an auto_ptr with
non-const copy operations.

Note that the promise of not becoming invalid cannot be kept for f(const X*)
either.

>void g( const auto_ptr<X>&x ) {
> // ... x ok
> f(x);
> // ... oops
>}
>void h() {
> auto_ptr<X> p( new X );
> // p valid
> g(x);
> // p bad. Undetected by the compiler because the standard
> // library class auto_ptr subverted the C++ type system
>}
>
>IMHO the only reasonable solution is to have two classes. If the committee
>only accepts one then users will have to write the other. That's ok, as
>long as it is obvious that auto_ptr isn't a general purpose smart_ptr. With

IMHO the only general purpose smart pointer is a garbage collected smart
pointer, which auto_ptr obviously is not.

>the current weird auto_ptr copy/op= perhaps users will have to write both
>the original and the ref counted class on their own. Or worse, they will
>actually use auto_ptr as if it was the rejected ref_counted ptr. This is a
>reasonable assumption because auto_ptr is the only standard smart ptr and
>users should be allowed to assume it is safe. It would be safe with private
>op=/copy as the original.

The original auto_ptr was so limited that important uses would require
the use of raw pointers and boolean flags, which are much less safe
techniques than the current auto_ptr. So you would need a counted_ptr
for those uses, but the overhead of counted_ptr is just too high. We
gave auto_ptr just enough copy semantics to support passing them to
functions and returning them from functions. As a result, it becomes
possible to use auto_ptr for some less safe idioms as well. Given the
infinity of unsafe idioms that C++ allows I just don't see the
problem.

>
>When designing a class for mass consumption it should not only support the
>intended idioms. It should also prevent missuse in common situations. The
>original does that. The current auto_ptr doesn't.
>

>Please reconsider John Max Skallers original proposal.
>
>(*) he has also mentioned other smart pointers here. holding arrays -
>block/ref-counted. copying pointers and cloning pointers using varying
>implementation techniques but AFAIK they were never proposed as standard
>classes.
>

I don't recall Max making such a proposal, though he made many
contributions to our discussion of smart pointers. I can assure you
that I would not insult the committee by asking them to reconsider a
proposal that they have rejected more than once already.

Greg Colvin
gre...@netcom.com
---

Pulkkinen Esa

unread,
Apr 15, 1996, 3:00:00 AM4/15/96
to
>In article <4kjcvb$g...@ugress.uib.no> bouk...@sentef1.fi.uib.no (Igor
>Boukanov) writes:
>|> auto_ptr<T>(const auto_ptr<T>&) to auto_ptr<T>(auto_ptr<T>&)
>|> and
>|> auto_ptr<T>& operator=(const auto_ptr<T>&) to
>|> auto_ptr<T>& operator=(auto_ptr<T>&)

IMHO, copy constructors for auto_ptr must be either private or
have non-const parameters.

In article <KANZE.96A...@gabi.gabi-soft.fr>,
J. Kanze <ka...@gabi-soft.fr> wrote:

>We've been through all this before. That was the original version.
>Regretfully, makes it impossible to return an auto_ptr from a function.
>And one of the more frequent uses of auto_ptr involves returning them
>from functions.

I can't really understand, why it should be possible to return
auto_ptr's from functions - why not define a distinct pointer type
for that purpose - and define conversion from auto_ptr to
that pointer type for returning it from functions. That is -
to return an auto_ptr from functions, you write:

taligent_ptr<T> f()
{ auto_ptr<T> p=new T;
return p;
}

(I have no idea if the 'taligent_ptr' is suitable for this kind of thing,
but its name is as good as any for this example .... )
--
Esa Pulkkinen | C++ programmers do it virtually
E-Mail: es...@cs.tut.fi | everywhere with a class, resulting
WWW : http://www.cs.tut.fi/~esap/ | in multiple inheritance.
---

Wil Evers

unread,
Apr 15, 1996, 3:00:00 AM4/15/96
to
In article <316F533D...@cantrip.org> Nathan Myers <n...@cantrip.org>
writes:

> Greg Colvin wrote:
>
> > In article <009A0A5CE115...@ittpub.nl> "Wil Evers"
> > <w...@ittpub.nl>:
> > >What I definitely do not understand is why the new auto_ptr template
> > >doesn't even allow us to query if it is actually owning the object
> > >pointed to.
>
> > I found it very hard to contrive examples where is_owner() would
> > actually be useful.
>
> I agree with Greg here: any code that is intended to execute
> differently, depending on the value returned by putative member
> auto_ptr<>::is_owner(), is just bad code.
>
> [snip]

>
> The answer is: it's your responsibility to keep track of ownership
> of pointers; if you can't do it manually, then automate it with
> reference counting or something. That's not what auto_ptr<> is for;
> its purpose is to make sure that the value "new T" gets destroyed.
> It does that job perfectly; don't ask it to do your job too.

Well, that's all a matter of interpretation. The previous, simpler,
implementation of auto_ptr used to do that job for me. I used to rely on
the guarantee that if it was pointing at something, it was pointing at
something alive and unique. It seemed to me that this was a reasonable
assumption because the DWP stated that auto_ptr implemented the concept of
`strict ownership'.

Imagine, for instance, a collection of ten heap objects in a polymorphic
hierarchy, where each of those is in one of three sets. Once every now and
then, some of the objects are moved from one of the sets to another. Why
would it be bad code to implement each of these sets using an array of ten
auto_ptrs? It seems to me there is nothing inherently good or bad about
such a design, it's just not supported any more.

The fact of the matter is that auto_ptr implements both a guarantee about
the deletion of the pointee when the auto_ptr is destroyed *and* a concept
of transferable object ownership. The `pointer part' of the auto_ptr
abstraction is well supported in its interface, while the `ownership part'
no longer is.

In one of his previous articles, Greg said that he hated the idea of
exposing the mutable `owner' member through an access function. Normally,
I would agree, but I think auto_ptr is a special case. The `owner' flag
has not been made mutable because it represents some implementation detail
that does not effect the logical state of the object; it has been made
mutable because of the problems with returning object ownership from
functions. One of the rules I use in my class designs is that if a certain
attribute is part of the logical state of an object, users should be able
to query it.

- Wil

J. Kanze

unread,
Apr 15, 1996, 3:00:00 AM4/15/96
to
In article <1996041216...@jabba.lehman.com> aj...@lehman.com
(Ajay Kamdar) writes:

|> In article <KANZE.96A...@gabi.gabi-soft.fr>,
|> J. Kanze <ka...@gabi-soft.fr> wrote:

Well, I agree fully that it is bad programming practice to let
exceptions propagate out of a destructor. At present, however, it is
legal C++ (although if the committee were to declare it undefined
behavior, they wouldn't get any objections from me), and as such, should
be taken into consideration when designing a *standard* library
component. (I *don't* take it into consideration when designing my own
components. But: if you don't like my style, you aren't obliged to use
my components. Everyone has to use the standard components, however.)

|> [snip]
|> >
|> >|> So which one is better for the C++ programmer? An approach
|> >|> which can lead to disastorous surprises at run-time
|> >|> (auto_ptr with copy semantics approach) definitely does
|> >|> not look the right choice under any stretch of imagination.
|> >
|> >In short, you are suggesting that memory leaks are OK, as long as they
|> >don't occur too often. This isn't the case for my applications.


|> Applications which cannot tolerate even occasional memory leaks
|> when exceptions propagate through destructors (if they are
|> lucky to live past those exceptions) should go through sufficient
|> testing to find all such occurences. Enough memory leak detection
|> tools exist on the market to make this possible. The onus
|> of finding those leaks is on those applications. Alternatively
|> they could use garbage collection. Given that even an auto_ptr

^^^^^^^^^^^^^^^^^^

Would that it were. But if this were really true (for portable
programs), then we wouldn't have to argue the point about auto_ptr,
would we? There'd be no need of the class in any of its forms. (I'll
trade you namespaces, RTTI and exceptions for garbage collection.)

|> having copy semantics does not really solve the problem with
|> exceptions emnating from destructors, I have a hard time buying
|> into warping the auto_ptr design and making it unsafe for
|> everyone to support such applications.

|> Moreover, if the unsafe copy semantics are moved out of auto_ptr
|> into taligent_ptr, applications which are willing to accept
|> the unsafe semantics and the lack of a complete solution inspite
|> of sacrificing safety can always use the taligent_ptr. But it
|> would be a *choice* that is not imposed upon everyone using the
|> standard auto_ptr class.

I'm not going to reiterate my arguments, since I really have nothing to
add. I understand your position, and in fact largely agree with the
points you have made. I just feel that there are other issues involved
which are more important. (I also feel that the only real solution is
garbage collection, which allows the semantics I want with the safety
you want. Maybe if commercial providers will start implementing
something like the Boehm collector as an extension, we will have the
existing practice necessary to get it into the next revision.)


--
James Kanze (+33) 88 14 49 00 email: ka...@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung

David Vandevoorde

unread,
Apr 15, 1996, 3:00:00 AM4/15/96
to
>>>>> "JK" == J Kanze <ka...@gabi-soft.fr> writes:
[...]
JK> Well, I agree fully that it is bad programming practice to let
JK> exceptions propagate out of a destructor. At present, however, it
JK> is legal C++ (although if the committee were to declare it
JK> undefined behavior, they wouldn't get any objections from me), and
JK> as such, should be taken into consideration when designing a
JK> *standard* library component. (I *don't* take it into
JK> consideration when designing my own components. But: if you don't
JK> like my style, you aren't obliged to use my components. Everyone
^^^^^^^^
JK> has to use the standard components, however.)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I would like to contest that ;-)

Given the kind of overhead in the ``auto_ptr nouveau'', I'm unlikely
to want to use it... and nothing prevents me from that. As far as I
know, auto_ptr does not have any connections with the rest of the
language (i.e., if it were dropped, there would be no repercussions).
Furthermore, it's really not hard to fashion a auto_ptr-like template
that fits one's desired semantics.

In that light, it seems to me that a standard auto_ptr is a little
overkill... Fortunately, I'm not forced to use it and so don't care
too much.

Daveed

James Kanze US/ESC 60/3/141 #40763

unread,
Apr 16, 1996, 3:00:00 AM4/16/96
to std...@ncar.ucar.edu
In article <xsospe5...@juicer.cs.rpi.edu> vand...@cs.rpi.edu
(David Vandevoorde) writes:

|> >>>>> "JK" == J Kanze <ka...@gabi-soft.fr> writes:
|> [...]
|> JK> Well, I agree fully that it is bad programming practice to let
|> JK> exceptions propagate out of a destructor. At present, however, it
|> JK> is legal C++ (although if the committee were to declare it
|> JK> undefined behavior, they wouldn't get any objections from me), and
|> JK> as such, should be taken into consideration when designing a
|> JK> *standard* library component. (I *don't* take it into
|> JK> consideration when designing my own components. But: if you don't
|> JK> like my style, you aren't obliged to use my components. Everyone
|> ^^^^^^^^
|> JK> has to use the standard components, however.)
|> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|> I would like to contest that ;-)

Yes. I should have said: everyone should be able to use the standard
components.

|> Given the kind of overhead in the ``auto_ptr nouveau'', I'm unlikely
|> to want to use it... and nothing prevents me from that. As far as I
|> know, auto_ptr does not have any connections with the rest of the
|> language (i.e., if it were dropped, there would be no repercussions).
|> Furthermore, it's really not hard to fashion a auto_ptr-like template
|> that fits one's desired semantics.

|> In that light, it seems to me that a standard auto_ptr is a little
|> overkill... Fortunately, I'm not forced to use it and so don't care
|> too much.

The problem is one of maintainance. I'm fairly sure that most of the
readers of this forum would have no difficulty crafting a variant of
auto_ptr which is exactly adapted to their particular style. Doing so,
however, means one more thing to learn for anyone trying to maintain
your code. So if the standard class comes anywhere close to what I
want or need, I will be using it, instead of my own.

Note that almost by definition, a standard class is not optimal for a
particular use. What makes it valuable as a standard is that it is
adequate for a wide range of uses. If some part of your application
makes intensive use of this class, you might want to declare a typedef,
to facilitate changing it later, if profiling really does show a
problem. (My experience is that it's amazing how rarely such things
really are a problem, and that generally, they aren't what you were
expecting anyway.)
--
James Kanze Tel.: (+33) 88 14 49 00 email: ka...@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils, études et réalisations en logiciel orienté objet --
-- A la recherche d'une activité dans une region francophone

0 new messages