Sign in to follow this  

auto_ptr

This topic is 4376 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I decided to finally break down and learn the STL in detail. So I'm wondering people's opinion on using auto_ptr. Specifically just making every pointer an auto_ptr unless some other type of smart pointer is more appropriate. Particularly whether it wouldn't be better to limit it to scenerios where a single delete statement wouldn't handle freeing the object properly or for which it might not be clear who is responsible for freeing the object.

Share this post


Link to post
Share on other sites
Go get a copy of accelerated C++ by Koenig and Moo.

You will learn all of the STL you need.

As far as pointers go, if you do c++ properly you should never need to call new or delete. Between the container classes and the auto_ptr type (and boost's smart pointers), you should be fully covered.

Also, see this list. As it says, read them mostly in order. You might need something down the list before you get to it.

frob.

Share this post


Link to post
Share on other sites
The drawback with auto_ptr is that you cannot safely put it into an stl container. The advantage of using auto_ptr is that it saves you in situation where exception handling code might bypass the code to delete the pointer. It provides a very simple but effective safety net. It's got it's uses, but it's not the magic bullet.

Share this post


Link to post
Share on other sites
I'll second Koenig&Moo -- it's the only introductory C++ book that I know that teaches you to code C++ and not C-with-classes.

Quote:
Original post by frob
As far as pointers go, if you do c++ properly you should never need to call new or delete. Between the container classes and the auto_ptr type (and boost's smart pointers), you should be fully covered.


New is still nessesary for polymorphism and non-auto lifetimes, but agreed -- you should never be calling delete ( or fclose() or closesocket() or ... ) except in the destructor of a RAII class.

Once nice use of auto_ptr is returning from a clone() function -- if they ignore it or don't explicitly do something stupid, then it wont leak. I also like it for accepting pointers, because a function taking an auto_ptr by value makes it very clear that you're taking over the lifetime management of that object.

As for containers of polymorphic objects, also consider The Boost Pointer Container Library. You can treat a ptr_vector<Base> almost liek a vector<Base&> -- the extra dereference ( an implementation detail of storing pointers for polymorphism ) is done for you. It also deletes and clones where nessesary so there's no reference counting needed.

Of course, if you're keeping handles to the objects in your container, you might still want a std::container of shared_ptrs so you can have weak_ptr handles.

Share this post


Link to post
Share on other sites
Quote:
Original post by LilBudyWizer
Particularly whether it wouldn't be better to limit it to scenerios where a single delete statement wouldn't handle freeing the object properly or for which it might not be clear who is responsible for freeing the object.


I don't use delete anymore, I exclusively use boost::scoped_ptr for when I would do new/code/delete, and boost::shared_ptr when the pointer needs to be passed around or stored. std::auto_ptr has it's places but I don't use it unless it is for some reason difficult to use the boost ptrs, or if a dependency on boost is unacceptable.

Similarly I use boost::*_array and boost::mutex::scoped_lock. Basically anywhere you have to call something at the beginning of a function and at the end, use a "smart" or scoped solution - it's mostly exception-safe and will free you to insert return's anywhere in the function.

Share this post


Link to post
Share on other sites
I often use std::auto_ptr as the return value from functions (though Washu dislikes that practice). Otherwise mostly I use boost::shared_ptr.

Share this post


Link to post
Share on other sites
Quote:
Original post by LilBudyWizer
I decided to finally break down and learn the STL in detail. So I'm wondering people's opinion on using auto_ptr. Specifically just making every pointer an auto_ptr unless some other type of smart pointer is more appropriate. Particularly whether it wouldn't be better to limit it to scenerios where a single delete statement wouldn't handle freeing the object properly or for which it might not be clear who is responsible for freeing the object.


Generally speaking, some other pointer type is more appropriate.

The best use of std::auto_ptr is when you have a member of a class that is a pointer. For example,

#include <memory>

class X;

class C
{
public:
void f() { m_x = std::auto_ptr<X>(new X); }

private:
std::auto_ptr<x> m_x;
};


This has the advantage that you don't need to write your own destructor to delete m_x, the default destructor will do the right thing, and the compiler will not let you accidentally copy the object, resulting in a double deletion (the bane of pointer members). You will have to write your own copy constructor and operator= if you want to copy such objects.

Using std::auto_ptr this was is very similar to having members that are references, except that references muct be bound at object construction time, whereas std:auto_ptrs can be set later (after, say, reading your configuration file).

--smw

Share this post


Link to post
Share on other sites
For general use I think the Boost smart pointer library is much better than std::auto_ptr. Of particular interest are both the enable_shared_from_this class and the ability to specify custom deleters for your pointer. This latter is particularly useful. For example, you can keep a COM interface pointer inside a shared_ptr, and have it call the Release() member function whenever it goes out of scope. I find this a remarkably convenient way of dealing with COM objects because I absolutely hate their manual reference counting. Between boost::shared_ptr and boost::scoped_ptr, the only real use for std::auto_ptr is for when you want to enforce single ownership but not noncopyable semantics, which really isn't that often in my experience. I think its best use is mentioned up above by me22 in that passing a std::auto_ptr to a class makes it very clear that the class intends to take over lifetime ownership of that memory.

Overall though, I'd definitely recommend using smart pointers wherever possible. I, like some who have posted before me, almost never actually use delete anymore when I'm programming in C++.

Share this post


Link to post
Share on other sites
Playing with it a bit and reading the posts I have to conclude it isn't a good "none of the above" smart pointer.

I don't know to what degree Boost is an option. BCB6 is supported, but as soon as they release it I'm upgrading to BDS2006. It just seems it would make most sense to wait until Boost actually has the workarounds specific to BDS2006 incorporated since I have no code currently using it. Particularly since as soon as BDS2006 arrives I have higher priority things to do. I'm a long ways out from starting an engine in earnst so Boost doesn't seem a high priority for experimental code. By the time I'm ready there will most likely be a patch to BDS2006 and an update to Boost with workarounds specific to BDS2006 incorporated.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by Bregma

...
#include <memory>

class X;

class C
{
public:
void f() { m_x = std::auto_ptr<X>(new X); }

private:
std::auto_ptr<x> m_x;
};


This has the advantage that you don't need to write your own destructor to delete m_x, the default destructor will do the right thing, ...


No it won't, in this case. It will ONLY be deleted properly if the class has a non-default destructor. Otherwise, the forward declaration in the header is not enough information for the compiler to create a destructor of the member object. I got bit by this a long time ago. Won't make that mistake again.

For another interesting thing you can do with pointer wrappers, you can look at: http://www.codeproject.com/cpp/TwoThirdsPimpl.asp.

David

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Quote:
Original post by Bregma
This has the advantage that you don't need to write your own destructor to delete m_x, the default destructor will do the right thing, ...


No it won't, in this case.


It won't even compile without X defined ("new X" is invalid at that point in this translation unit otherwise)

Quote:
It will ONLY be deleted properly if the class has a non-default destructor.


Not true - for both MSVC++ 2k5 and GCC 3.4.2, if X is defined in the same translation unit (even if forward declared originally as above) ~X is properly called.

The issue you're thinking of occurs when:

1) You destroy the containing object (of type C) in a translation unit T
2) The containing object (of type C) uses a default destructor.
3) You never define the contained type (X) in translation unit T.

#include <memory>
#include <iostream>

class X;

class C
{
private:
std::auto_ptr< X > m_x;
public:
C(); //deffered until X defined
//default destructor
};

int main () {
C c;
} //result: ~X when c goes out of scope.

class X { public: ~X() { std::cout << "~X" << std::endl; } };

C::C() : m_x( new X ) {}



Any compiler claiming to be modern should display a warning when invoking such behavior. Both MSVC++ 2k5 and GCC 3.4.2 do at least, with default settings.

There is an alternative scenario:

1) You destroy the containing object (of type C).
2) The containing object (of type C) uses a non-default destructor, defined in translation unit T.
3) You never define the contained type (X) in translation unit T.

MSVC++ 2k5 dosn't seem to catch this one, oddly. GCC 3.4.2 generates warnings.


// c.hpp ////////////////
#include <memory>
class X;
class C
{
private:
std::auto_ptr< X > m_x;
public:
C(); //deffered until X defined
~C();
};

// x.cpp ////////////////
#include <iostream>
#include "c.hpp"
class X { public: ~X() { std::cout << "~X" << std::endl; } };
C::C() : m_x( new X ) {} //here because we need X defined to new it.

// c.cpp ////////////////
#include "c.hpp"
C::~C() {} //here because we need X not defined to show the problem

// main.cpp /////////////
#include "c.hpp"
int main () {
C c;
} //result: no ~X


Both these scenarios have 1 thing in common: X's destructor is not defined in the same translation as C's, whether C's is compiler generated ("default") or explicit.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by MaulingMonkey
...Not true...


Knee-jerk reaction. Didn't see the ctor defined in the definition, and thought it was a header...

Merry Christmas!
David

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Quote:
Original post by MaulingMonkey
...Not true...


Knee-jerk reaction. Didn't see the ctor defined in the definition, and thought it was a header...


It could be... a sane reason for a forward decleration, followed by an actual definition later on, within a header, would be a circular dependancy (with f being implicitly inline).

I just hate not-quite-truths, so I felt the need to clarify. But it was good to bring up.

Share this post


Link to post
Share on other sites

This topic is 4376 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this