Thread View: comp.std.c++
5 messages
5 total messages
Started by Greg Colvin
Fri, 26 Jan 1996 15:47
Cleaning auto_ptr copy semantics.
Author: Greg Colvin
Date: Fri, 26 Jan 1996 15:47
Date: Fri, 26 Jan 1996 15:47
158 lines
6760 bytes
6760 bytes
Our working paper's auto_ptr (20.4.5) specifies a non-const copy constructor
and assignment operator. This specification makes functions that return
auto_ptr less useful than I intended, due to a language restriction on
modifying temporaries. Since changing the language specification seems not
to be an option, a change to auto_ptr is in order.
The smallest change I can see that preserves the semantics of strict
ownership is to separate the concepts of "holding a pointer" and "owning
an object", so that more than one auto_ptr can hold a pointer to an object,
but only one auto_ptr can own the object.
Note that only the held pointer is directly accessible; which auto_ptr
owns an object is observable only via the side effects of destructor calls.
Thus providing const arguments to the copy constructor and assignment
operator and making release() a const function seem to me a reasonable
case of "logical constness".
Note also that reset() must go, since the idiom p.reset(q.release())
cannot safely transfer ownership. I would happily remove get() as well,
since its primary use may turn out to be leaking pointers.
A simple implementation makes the semantics clear:
template<class X> class auto_ptr {
X* px;
mutable bool owner;
public:
explicit auto_ptr(X* p=0) : px(p), owner(true) {}
template<class Y>
auto_ptr(const auto_ptr<Y>& r) : px(r.release()), owner(true) {}
template<class Y>
auto_ptr& operator=(const auto_ptr<Y>& r) {
if (&r != this) {
if (owner) delete px; else owner = true;
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 = false; return px; }
};
This implementation is slightly bigger (one bool) and slightly slower
(two extra tests and two and one-half extra assignments across eight
functions) than the comparable implementation of the WP semantics. On
some hardware it might make sense to save space at the cost of masking
off the ownership bit or trapping memory hardware interrupts.
The changed Working Paper text I plan to propose at Scotts Valley is:
20.4.5 Template class auto_ptr [lib.auto.ptr]
Template auto_ptr holds onto a pointer to an object obtained via new
and deletes that object when it is the owner of that object and it
itself is destroyed (such as when leaving block scope 6.7).
namespace std {
template<class X> class auto_ptr {
public:
// 20.4.5.1 construct/copy/destroy:
explicit auto_ptr(X* p=0);
template<class Y> auto_ptr(const auto_ptr<Y>&); |
template<class Y> auto_ptr& operator=(const auto_ptr<Y>&); |
~auto_ptr();
// 20.4.5.2 members:
X& operator*() const;
X* operator->() const;
X* get() const; ?
X* release() const; |
|
};
}
The auto_ptr provides a semantics of strict ownership. After initial |
construction an auto_ptr owns the object it holds a pointer to. An |
object may be safely owned by only one auto_ptr, so copying an auto_ptr |
copies the pointer and transfers ownership to the destination. |
20.4.5.1 auto_ptr constructors [lib.auto.ptr.cons]
explicit auto_ptr(X* p = 0);
Requires:
p points to an object of type X or a class derived from X for which
delete p is defined and accessible, or else p is a null pointer.
Postconditions:
*this holds the pointer p. |
*this is the owner of the object **this. |
template<class Y> auto_ptr(const auto_ptr<Y>& a); |
Requires:
Y is type X or a class derived from X for which delete(Y*) is
defined and accessible.
Effects:
Calls a.release().
Postconditions:
*this holds the pointer returned from a.release(). |
*this is the owner of the object **this. |
template<class Y> auto_ptr<X>& operator=(const auto_ptr<Y>& a); |
Requires:
Y is type X or a class derived from X for which delete(Y*) is
defined and accessible.
Effects:
If *this is the owner of **this and this != &a then delete &**this. |
Calls a.release().
Returns:
*this.
Postconditions:
*this holds the pointer returned from a.release(). |
*this is the owner of the object **this. |
~auto_ptr();
Effects:
If *this is the owner of **this then delete &**this. |
20.4.5.2 auto_ptr members [lib.auto.ptr.members]
X& operator*() const;
Requires:
get() != 0
Returns:
A reference to the object pointed to by the pointer held by *this. |
X* operator->() const;
Returns:
The pointer held by *this. |
X* get() const; ?
?
Returns: ?
The pointer held by *this. |?
X* release() const; |
Returns:
The pointer held by *this. |
Postcondition:
*this is not the owner of the object **this. |
|
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: Cleaning auto_ptr copy semantics.
Author: Richard Henderson
Date: Thu, 01 Feb 1996 02:01
Date: Thu, 01 Feb 1996 02:01
58 lines
2735 bytes
2735 bytes
In article <gregorDLrrun.K2x@netcom.com>, Greg Colvin <gregor@netcom.com> wrote: >The smallest change I can see that preserves the semantics of strict >ownership is to separate the concepts of "holding a pointer" and "owning >an object", so that more than one auto_ptr can hold a pointer to an object, >but only one auto_ptr can own the object. The problem I see with this is that a holder cannot see when an object goes away. With the old transfer of control semantics, there is never a dangling pointer to an object. Dangling pointers are, in my opinion, much more dangerous than NULL pointers. Also, I see no difference, wrt temporaries, between your solution and making "px" mutable. Both solutions actually change the temporary. >Note also that reset() must go, since the idiom p.reset(q.release()) >cannot safely transfer ownership. I would happily remove get() as well, >since its primary use may turn out to be leaking pointers. Without get(), how do you (without moving to full reference counting, which I think should exist _along side of_ auto_ptr) pass auto_ptr<foo> a; to a function bar(), and retain control of the object after bar() terminates? The current extern void bar(foo *); bar(a.get()); is quite satisfactory. On the other hand extern void bar(foo *); foo *tmp = a.release(); bar(tmp); a.reset(tmp); violates one of the main reasons for having auto_ptr (cleaning up on the way out of an exception within bar()), and extern void bar(const auto_ptr<foo> &); bar(a); destroys a's object when bar returns (if nothing happens within bar() to cause it to be destroyed sooner) under both the original semantics and your revised semantics. > template<class Y> auto_ptr(const auto_ptr<Y>&); | > template<class Y> auto_ptr& operator=(const auto_ptr<Y>&); | I do like the template members though. r~ --- [ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu. Contact address: std-c++-request@ncar.ucar.edu. The moderation policy is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: Cleaning auto_ptr copy semantics.
Author: James Kanze US/ESC 60/3/141 #407...
Date: Thu, 01 Feb 1996 15:53
Date: Thu, 01 Feb 1996 15:53
63 lines
3274 bytes
3274 bytes
In article <gregorDLrrun.K2x@netcom.com> gregor@netcom.com (Greg
Colvin) writes:
|> Our working paper's auto_ptr (20.4.5) specifies a non-const copy constructor
|> and assignment operator. This specification makes functions that return
|> auto_ptr less useful than I intended, due to a language restriction on
|> modifying temporaries. Since changing the language specification seems not
|> to be an option, a change to auto_ptr is in order.
I'll admit that I was toying with the idea of a change in the language
specification. The problem does not just affect auto_ptr. I have a
number of functions for which the user typically will want to pass a
temporary, but which will modify this temporary.
While toying with this last night, it occured to me that there is a
very simple solution: add an `asLValue' function:
template< class T >
class auto_ptr
{
public :
auto_ptr< T >& asLValue()
{
return *this ;
}
// ...
} ;
This allows leaving the parameters to operator= and the copy
constructor non-const, but will permit assigning/copying the return
value of a function, by explicitly invoking `asLValue':
auto_ptr< T > f() ;
auto_ptr< T > p1( f().asLValue() ) ;
p1 = f().asLValue() ;
This gives auto_ptr the semantics I and Bill Gibbons felt important:
that the pointer is *never* released from an auto_ptr, but maintains
the definition of const desired by Fergus Henderson and others; a
const object is not modified, and a function which declares a
parameter as a const reference does not modify that parameter.
Note that in fact, the `asLValue' function is not const, and cannot be
called on a const object. It can be called on a temporary, though,
and since it returns a non-const l-value, its results can be bound to
a non-const reference (i.e.: the parameter to the copy constructor or
the assignment operator).
As this idea has just occured to me, I've not had the time to work out
all of the implications. (One thing is sure: it needs a better
name:-).) Still, I think it might be worth looking into.
--
James Kanze Tel.: (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils, itudes et rialisations en logiciel orienti objet --
-- A la recherche d'une activiti dans une region francophone
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Re: Cleaning auto_ptr copy semantics.
Author: Joe Buck
Date: Fri, 02 Feb 1996 21:54
Date: Fri, 02 Feb 1996 21:54
40 lines
2385 bytes
2385 bytes
gregor@netcom.com (Greg Colvin) writes:
>The smallest change I can see that preserves the semantics of strict
>ownership is to separate the concepts of "holding a pointer" and "owning
>an object", so that more than one auto_ptr can hold a pointer to an object,
>but only one auto_ptr can own the object.
Your new proposal is a recipe for dangling pointers. What about the
following program:
main () {
auto_ptr<int> outer = new int;
{
auto_ptr<int> inner = outer; // inner now owns the int
// end of inner's scope, int is deleted
}
*outer = 1; // crash
}
Under the old rules for auto_ptr, after the copy constructor for inner,
outer's internal pointer would be null, and I could test for this
(outer.get() == 0). Under your proposed change, though, outer contains
a dangling pointer.
I don't see a way around reference counts if you want a class that
contains a pointer and can do copies and assignments using the expected
semantics and guarantees to clean up the heap object.
We could still have plain auto_ptr, but with no assignment operator and no
copy constructor, and with an explicit member function for transferring
ownership. This means that a function cannot return an auto_ptr, but it
could still return one through a reference parameter.
--
-- Joe Buck <jbuck@synopsys.com> (not speaking for Synopsys, Inc)
Work for something because it is good,
not just because it stands a chance to succeed. -- Vaclav Havel
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy is
in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]
Re: Cleaning auto_ptr copy semantics.
Author: John Max Skaller
Date: Mon, 05 Feb 1996 17:29
Date: Mon, 05 Feb 1996 17:29
81 lines
3991 bytes
3991 bytes
Joe Buck wrote:
>
> gregor@netcom.com (Greg Colvin) writes:
> >The smallest change I can see that preserves the semantics of strict
> >ownership is to separate the concepts of "holding a pointer" and "owning
> >an object", so that more than one auto_ptr can hold a pointer to an object,
> >but only one auto_ptr can own the object.
>
> Your new proposal is a recipe for dangling pointers.
It is not Greg's current proposal which is
a recipe for disaster, it is the very notion of using
the copy operator to transfer ownership. IMHO.
> I don't see a way around reference counts if you want a class that
> contains a pointer and can do copies and assignments using the expected
> semantics and guarantees to clean up the heap object.
I agree completely.
> We could still have plain auto_ptr, but with no assignment operator and no
> copy constructor, and with an explicit member function for transferring
> ownership. This means that a function cannot return an auto_ptr, but it
> could still return one through a reference parameter.
Again, I agree completely, this was my original proposal:
TWO classes, one which was to be used simply to attach heap objects onto
the stack to allow the destructor to delegate to destroying the
heap object. This fixes the problem:
void f() {
X* x= new X;
throw 1; // WOOPS,
delete x;
}
Since C++ stack frames are not copyable, copyability
in auto_ptr is not only not required, it's dangerous. The concept
is simply to SCHEDULE deletion at the point of construction:
void f() {
auto_ptr<X> x (new X); // SCHEDULES DELETION at #1
throw 1; // OK: invokes block termination code
// #1: termination code "delete x;" scheduled
}
This leaves the problem of pointers in copyable
objects -- for which reference counting is a solution
in acyclic cases.
The problem with the "move" semantics of
the current auto_ptr is NOT the strict ownership
idiom -- it's the use of inappropriate copy syntax to
access that idiom.
The solution -- IMHO -- is to ignore and NOT USE
auto_ptr, and take up where the committee failed:
attempt to obtain consensus amoung USERS on suitable
smart pointer classes. "Practice" will then push such
accepted and "in use" classes in to the _next_ standard.
My UESTL/smart module is an attempt to provide
a coherent set of smart pointers. Mail me for a copy,
email comments welcome. [It's unclear if the charter of this
newsgroup allows for "public" comment on my "private"
attempt at standardisation. But the results will be published
in black and white by Prentice Hall. Someone has to
do this, since the committee wasn't able to. The set of
classes I have shows why the committe had trouble: more
than one class is required.]
--
John Max Skaller voice: 61-2-566-2189
81 Glebe Point Rd fax: 61-2-660-0850
GLEBE NSW 2037 web: http://www.maxtal.com.au/~skaller/
AUSTRALIA email: skaller@maxtal.com.au
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy is
in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads