I cannot see the need for auto_ptr?!

J

Jamie Burns

Hello,

I realise that I just dont get this, but I cannot see the need for auto_ptr.
As far as I have read, it means that if you create an object using an
auto_ptr, instead of a raw pointer, then the object will get cleaned up when
the method/function ends. Isn't this what happens if you just declare an
object without using a pointer at all? Aren't these examples the same (I
know they will not be, but I am hoping someone may explain to me what I am
missing here!):

void f()
{
T t;
t.SomeFunc();
} // cleanup when function ends

void f()
{
auto_ptr<T> pt(new T);
pt->SomeFunc();
} // cleanup when function ends

Wish I could see what is going on here!

Jamie.
 
L

lilburne

Jamie said:
Hello,

I realise that I just dont get this, but I cannot see the need for auto_ptr.
As far as I have read, it means that if you create an object using an
auto_ptr, instead of a raw pointer, then the object will get cleaned up when
the method/function ends. Isn't this what happens if you just declare an
object without using a pointer at all? Aren't these examples the same (I
know they will not be, but I am hoping someone may explain to me what I am
missing here!):

void f()
{
T t;
t.SomeFunc();
} // cleanup when function ends

void f()
{
auto_ptr<T> pt(new T);
pt->SomeFunc();
} // cleanup when function ends

Wish I could see what is going on here!

What is required is that the object T is destructed when it
is no longer used and the memory it occupied is returned to
the system. With stack based objects (your first example)
this happens automatically when the object goes out of
scope, but with heap based objects (your second example)
this doesn't occur when a bare pointer goes out of scope.
auto_ptr being a stack based object gets destroyed
automatically, and in the process destroys the heap based
object T that the auto_ptr contains.
 
J

Jamie Burns

OK, so maybe I don't get why you wouldn't just allocate T on the stack? Is
that a bad thing to do? Why go out of your way to allocate on the heap if it
requires this type of attention to cleanup?

Jamie.
 
T

Thore B. Karlsen

OK, so maybe I don't get why you wouldn't just allocate T on the stack?

Because you want it to live longer than it would on the stack.
Is that a bad thing to do? Why go out of your way to allocate on the heap if
it requires this type of attention to cleanup?

Because it is very often the right thing to do.
 
J

Jamie Burns

But if I want it to live longer, surely I wouldn't be using an auto_ptr in
the first place (as it won't live past the end of the function that created
it) ?!

This is what I cannot grasp.

In terms of lifetime, T on the stack, and an auto_ptr<T> on the heap are the
same, no?

If so, that just leaves "Because it is very often the right thing to do",
which whilst I am sure is a sincere opinion, doesn't help me to understand.

:eek:(

Jamie.
 
L

lilburne

Jamie said:
But if I want it to live longer, surely I wouldn't be using an auto_ptr in
the first place (as it won't live past the end of the function that created
it) ?!

Correct in general but you may want to return one, or you
may have to take ownership of a bare pointer returned from
some thing else.
This is what I cannot grasp.

Sometimes you have no option but to create something on the
heap (say the object is very big)
 
G

Guest

Hello,

I realise that I just dont get this, but I cannot see the need for
auto_ptr.
As far as I have read, it means that if you create an object using an
auto_ptr, instead of a raw pointer, then the object will get cleaned up
when
the method/function ends. Isn't this what happens if you just declare an
object without using a pointer at all? Aren't these examples the same (I
know they will not be, but I am hoping someone may explain to me what I
am
missing here!):

void f()
{
T t;
t.SomeFunc();
} // cleanup when function ends

void f()
{
auto_ptr<T> pt(new T);
pt->SomeFunc();
} // cleanup when function ends

Wish I could see what is going on here!

Jamie.

You are right, auto_pointer is unnecessary.
One reason to use dynamic allocation is to allocate array of the size
known at the run time. std::vector deals with it.
Second reason could be to create an object which polymorphic type is known
at the run time. Then we could use :
template <class Type> type_dependent_code(Type *p) {
Type data;
data.SomeFunc(); };
void f() {
determine the TYPE;
type_dependent_code(static_cast<TYPE*>(0));
};


Returning pointer to dynamically allocated object is not a good idea
anyway.
 
L

lilburne

Returning pointer to dynamically allocated object is not a good idea
anyway.

Returning large objects on the stack is a worse idea.

// performance killer
vector<Point3D> calculate_some_geometry()
{

vector<Point3D> geometry;

// do something that adds lots of points to geometry

return geometry;
}
 
T

Thore B. Karlsen

But if I want it to live longer, surely I wouldn't be using an auto_ptr in
the first place (as it won't live past the end of the function that created
it) ?!

This is what I cannot grasp.

In terms of lifetime, T on the stack, and an auto_ptr<T> on the heap are the
same, no?

Yes, but you can return the auto_ptr, in effect just returning a pointer
instead of a copy-constructed object which might be expensive or (as is
often the case) impossible, or just not the right thing to do. Or you
can have a big object that is only allocated when it's needed, but whose
lifetime is longer than the scope you're in. Or you can take ownership
of an existing raw pointer and have auto_ptr wrap it and deal with
deallocating it.

If you don't understand why it's necessary, don't worry about it. You
will immediately see its utility once you start writing programs that
are sufficiently complex.
 
G

Guest

Returning large objects on the stack is a worse idea.

// performance killer
vector<Point3D> calculate_some_geometry()
{

vector<Point3D> geometry;

// do something that adds lots of points to geometry

return geometry;
}

void calculate_some_geometry(vector<Point3D>& v);
 
B

Bob Nelson

Jamie Burns said:
I realise that I just dont get this, but I cannot see the need for auto_ptr.
As far as I have read, it means that if you create an object using an
auto_ptr, instead of a raw pointer, then the object will get cleaned up when
the method/function ends. Isn't this what happens if you just declare an
object without using a pointer at all? Aren't these examples the same (I
know they will not be, but I am hoping someone may explain to me what I am
missing here!):

The mechanism by which an auto_ptr ``transfers ownership'' to the
receiving call site makes it a very worthy addition to a C++ developer's
toolchest. (In particular, but realizing that threads are not defined
by the C++ language (hence the parens), it makes it easy to create a
pointer to an object in a routine that ``hands it off'' to a detached
thread).

Here's a toy example of the power afforded by auto_ptr. Note that the
call site need not be concerned with the destruction...that gets
handled when ``f()'' goes out of scope:

=========================== [ cut ] ===================================

#include <cassert>
#include <memory>

using namespace std;

struct C {
C(): i(42) {}
int i;
};

static void f(auto_ptr<C> p)
{
assert(p->i == 42);
assert(p.get());
}

int main()
{
auto_ptr<C> p(new C);

assert(p->i == 42);
assert(p.get());
f(p);
assert(!p.get());
}
 
G

Guest

The mechanism by which an auto_ptr ``transfers ownership'' to the
receiving call site makes it a very worthy addition to a C++ developer's
toolchest. (In particular, but realizing that threads are not defined
by the C++ language (hence the parens), it makes it easy to create a
pointer to an object in a routine that ``hands it off'' to a detached
thread).

But the idea of creating an object in a routine that hands it of to a
detached thread is not a good idea to start with.
Maybe if reference counted but transfering ownership , under threat ,
maybe.
Point is that the shared resources that are the source of the object
are limited. Owning resources that are shared ?
this was possible in 16 bit dos, maybe not so bad after all.
 
A

Alf P. Steinbach

I realise that I just dont get this, but I cannot see the need for auto_ptr.

Ah, well, isn't that in the FAQ?

Checking...

Nope, not all, but the FAQ does explain the merits of std::auto_ptr in the
presence of exceptions,
<url: http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.4>.

Okay, here goes, "std::auto_ptr for ze novice", by yours truly.

std::auto_ptr is currently the only example in the standard library of a
"smart pointer":


A "smart pointer" is an object that encapsulates a pointer and provides
all the operations that the encapsulated pointer has, plus, it provides
automatic deallocation.


The scheme used by std::auto_ptr is very basic: it transfers _ownership_
on assignment and copy construction (the last through a horrible hack).
If a std::auto_ptr object goes out of scope or is otherwise destroyed,
it will deallocate the object it's got a pointer to if and only it
currently owns that object. So as soon as you put a pointer into a
std::auto_ptr you know the pointed-to object will be deallocated sooner
or later; later, if you keep assigning that std::auto_ptr to other
std::auto_ptr's, thus transferring ownership of the object.

Now this is very useful for some oft-occurring situations. Say, for example,
that you want to return a largish object from a function. One way is

LargeObject* foo()
{
return new LargeObject();
}

But this is very unsafe, for who's gonna deallocate that object? There's
nothing about foo that indicates this. Some novice might write

void bar()
{
LargeObject* p = foo();

p->doTheFandango();
}

forgetting to deallocate the object, while a programmer with a year or two
of experience might write

void bar()
{
LargeObject* p = foo();

p->doTheFandango();
delete p;
}

forgetting that 'doTheFandango' might throw an exception, in which case
the object is not deallocated.

If, instead, you design 'foo' as


std::auto_ptr<LargeObject> foo()
{
return new LargeObject();
}

then whoever uses that function has to actively try to _avoid_ proper
deallocation in order to mess things up. The most natural is to write
client code like


void bar()
{
std::auto_ptr<LargeObject> p = foo();

p->doTheFandango();
}

where the call to 'foo' transfers ownership up to the local
std::auto_ptr in 'bar', which guarantees deallocation even if, as Murphy
guarantees will happen, 'doTheFandango' throws an exception.
 
L

lilburne

That's what i would do with the big data, wouldn't you ?

Not always, and I definitely wouldn't use a vector to store
it either.

You can get away with the reference if you know where the
data is going to end up, but say for example that
calculate_some_geometry() is destructive and may fail,
you'll want to do the calculation and only if it is OK
replace the original data. Taking over a pointer avoids a
final copy.
 
G

Guest

(e-mail address removed) wrote:
You can get away with the reference if you know where the data is going
to end up, but say for example that calculate_some_geometry() is
destructive and may fail, you'll want to do the calculation and only if
it is OK replace the original data. Taking over a pointer avoids a final
copy.

I am not getting it. Either your calculate_some_geometry() may fail or
not.
If it fails you need a copy , if it doesn't you don't.
So does it or doesn't it , probably this question doesn't belong here
because - as std says - it's undefined.
 
H

Howard Hinnant

Jamie Burns said:
Hello,

I realise that I just dont get this, but I cannot see the need for auto_ptr.
As far as I have read, it means that if you create an object using an
auto_ptr, instead of a raw pointer, then the object will get cleaned up when
the method/function ends. Isn't this what happens if you just declare an
object without using a pointer at all? Aren't these examples the same (I
know they will not be, but I am hoping someone may explain to me what I am
missing here!):

void f()
{
T t;
t.SomeFunc();
} // cleanup when function ends

void f()
{
auto_ptr<T> pt(new T);
pt->SomeFunc();
} // cleanup when function ends

Wish I could see what is going on here!

Imho, one of the best uses of auto_ptr is to ease making some other
operation exception safe. For example consider:

#include <memory>

template <class T>
class X
{
public:
explicit X(T* ptr);
private:
int* int_data_;
class T* ptr_;
};

template <class T>
X<T>::X(T* ptr)
{
std::auto_ptr<T> hold(ptr);
int_data_ = new int(1);
ptr_ = hold.release();
}

Here the semantics are that X<T> constructs with a T*, and retains
ownership of that pointer no matter what. In addition to retaining
ownership of the T*, X must also acquire some other resource at
construction time. Whether the construciton of X succeeds, or fails
with an exception being thrown, the T* must be managed, not leaked.

So the X(T*) constructor first establishes ownership of the passed in
ptr with an auto_ptr. This is a no-throw operation, guaranteed to
succeed. Now the constructor goes about its other business. If
anything following throws an exception, the local auto_ptr destructor
insures that the T* is properly cleaned up. After construction is
complete, the X officially takes ownership of the T* by transferring it
from the auto_ptr.

-Howard
 
G

Guest

Ah, well, isn't that in the FAQ?

Checking...

Nope, not all, but the FAQ does explain the merits of std::auto_ptr in
the
presence of exceptions,
<url: http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.4>.

Okay, here goes, "std::auto_ptr for ze novice", by yours truly.

std::auto_ptr is currently the only example in the standard library of a
"smart pointer":
void bar()
{
std::auto_ptr<LargeObject> p = foo();

p->doTheFandango();
}

where the call to 'foo' transfers ownership up to the local
std::auto_ptr in 'bar', which guarantees deallocation even if, as Murphy
guarantees will happen, 'doTheFandango' throws an exception.

Yes, but returning a pointer from foo is a bad progamming practice.
Why don't you just say that auto_ptr is deprecated ?
 
G

Guest

So the X(T*) constructor first establishes ownership of the passed in ptr
with an auto_ptr. This is a no-throw operation, guaranteed to succeed.
Now the constructor goes about its other business. If anything following
throws an exception, the local auto_ptr destructor insures that the T* is
properly cleaned up. After construction is complete, the X officially
takes ownership of the T* by transferring it from the auto_ptr.

And that's exactly the problem.


Why dynamic allocations in exceptions sensitive code ?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,111
Latest member
KetoBurn
Top