Related
I used to think C++'s object model is very robust when best practices are followed.
Just a few minutes ago, though, I had a realization that I hadn't had before.
Consider this code:
class Foo
{
std::set<size_t> set;
std::vector<std::set<size_t>::iterator> vector;
// ...
// (assume every method ensures p always points to a valid element of s)
};
I have written code like this. And until today, I hadn't seen a problem with it.
But, thinking about it a more, I realized that this class is very broken:
Its copy-constructor and copy-assignment copy the iterators inside the vector, which implies that they will still point to the old set! The new one isn't a true copy after all!
In other words, I must manually implement the copy-constructor even though this class isn't managing any resources (no RAII)!
This strikes me as astonishing. I've never come across this issue before, and I don't know of any elegant way to solve it. Thinking about it a bit more, it seems to me that copy construction is unsafe by default -- in fact, it seems to me that classes should not be copyable by default, because any kind of coupling between their instance variables risks rendering the default copy-constructor invalid.
Are iterators fundamentally unsafe to store? Or, should classes really be non-copyable by default?
The solutions I can think of, below, are all undesirable, as they don't let me take advantage of the automatically-generated copy constructor:
Manually implement a copy constructor for every nontrivial class I write. This is not only error-prone, but also painful to write for a complicated class.
Never store iterators as member variables. This seems severely limiting.
Disable copying by default on all classes I write, unless I can explicitly prove they are correct. This seems to run entirely against C++'s design, which is for most types to have value semantics, and thus be copyable.
Is this a well-known problem, and if so, does it have an elegant/idiomatic solution?
C++ copy/move ctor/assign are safe for regular value types. Regular value types behave like integers or other "regular" values.
They are also safe for pointer semantic types, so long as the operation does not change what the pointer "should" point to. Pointing to something "within yourself", or another member, is an example of where it fails.
They are somewhat safe for reference semantic types, but mixing pointer/reference/value semantics in the same class tends to be unsafe/buggy/dangerous in practice.
The rule of zero is that you make classes that behave like either regular value types, or pointer semantic types that don't need to be reseated on copy/move. Then you don't have to write copy/move ctors.
Iterators follow pointer semantics.
The idiomatic/elegant around this is to tightly couple the iterator container with the pointed-into container, and block or write the copy ctor there. They aren't really separate things once one contains pointers into the other.
Yes, this is a well known "problem" -- whenever you store pointers in an object, you're probably going to need some kind of custom copy constructor and assignment operator to ensure that the pointers are all valid and point at the expected things.
Since iterators are just an abstraction of collection element pointers, they have the same issue.
Is this a well-known problem?
Well, it is known, but I would not say well-known. Sibling pointers do not occur often, and most implementations I have seen in the wild were broken in the exact same way than yours is.
I believe the problem to be infrequent enough to have escaped most people's notice; interestingly, as I follow more Rust than C++ nowadays, it crops up there quite often because of the strictness of the type system (ie, the compiler refuses those programs, prompting questions).
does it have an elegant/idiomatic solution?
There are many types of sibling pointers situations, so it really depends, however I know of two generic solutions:
keys
shared elements
Let's review them in order.
Pointing to a class-member, or pointing into an indexable container, then one can use an offset or key rather than an iterator. It is slightly less efficient (and might require a look-up) however it is a fairly simple strategy. I have seen it used to great effect in shared-memory situation (where using pointers is a no-no since the shared-memory area may be mapped at different addresses).
The other solution is used by Boost.MultiIndex, and consists in an alternative memory layout. It stems from the principle of the intrusive container: instead of putting the element into the container (moving it in memory), an intrusive container uses hooks already inside the element to wire it at the right place. Starting from there, it is easy enough to use different hooks to wire a single elements into multiple containers, right?
Well, Boost.MultiIndex kicks it two steps further:
It uses the traditional container interface (ie, move your object in), but the node to which the object is moved in is an element with multiple hooks
It uses various hooks/containers in a single entity
You can check various examples and notably Example 5: Sequenced Indices looks a lot like your own code.
Is this a well-known problem
Yes. Any time you have a class that contains pointers, or pointer-like data like an iterator, you have to implement your own copy-constructor and assignment-operator to ensure the new object has valid pointers/iterators.
and if so, does it have an elegant/idiomatic solution?
Maybe not as elegant as you might like, and probably is not the best in performance (but then, copies sometimes are not, which is why C++11 added move semantics), but maybe something like this would work for you (assuming the std::vector contains iterators into the std::set of the same parent object):
class Foo
{
private:
std::set<size_t> s;
std::vector<std::set<size_t>::iterator> v;
struct findAndPushIterator
{
Foo &foo;
findAndPushIterator(Foo &f) : foo(f) {}
void operator()(const std::set<size_t>::iterator &iter)
{
std::set<size_t>::iterator found = foo.s.find(*iter);
if (found != foo.s.end())
foo.v.push_back(found);
}
};
public:
Foo() {}
Foo(const Foo &src)
{
*this = src;
}
Foo& operator=(const Foo &rhs)
{
v.clear();
s = rhs.s;
v.reserve(rhs.v.size());
std::for_each(rhs.v.begin(), rhs.v.end(), findAndPushIterator(*this));
return *this;
}
//...
};
Or, if using C++11:
class Foo
{
private:
std::set<size_t> s;
std::vector<std::set<size_t>::iterator> v;
public:
Foo() {}
Foo(const Foo &src)
{
*this = src;
}
Foo& operator=(const Foo &rhs)
{
v.clear();
s = rhs.s;
v.reserve(rhs.v.size());
std::for_each(rhs.v.begin(), rhs.v.end(),
[this](const std::set<size_t>::iterator &iter)
{
std::set<size_t>::iterator found = s.find(*iter);
if (found != s.end())
v.push_back(found);
}
);
return *this;
}
//...
};
Yes, of course it's a well-known problem.
If your class stored pointers, as an experienced developer you would intuitively know that the default copy behaviours may not be sufficient for that class.
Your class stores iterators and, since they are also "handles" to data stored elsewhere, the same logic applies.
This is hardly "astonishing".
The assertion that Foo is not managing any resources is false.
Copy-constructor aside, if a element of set is removed, there must be code in Foo that manages vector so that the respective iterator is removed.
I think the idiomatic solution is to just use one container, a vector<size_t>, and check that the count of an element is zero before inserting. Then the copy and move defaults are fine.
"Inherently unsafe"
No, the features you mention are not inherently unsafe; the fact that you thought of three possible safe solutions to the problem is evidence that there is no "inherent" lack of safety here, even though you think the solutions are undesirable.
And yes, there is RAII here: the containers (set and vector) are managing resources. I think your point is that the RAII is "already taken care of" by the std containers. But you need to then consider the container instances themselves to be "resources", and in fact your class is managing them. You're correct that you're not directly managing heap memory, because this aspect of the management problem is taken care of for you by the standard library. But there's more to the management problem, which I'll talk a bit more about below.
"Magic" default behavior
The problem is that you are apparently hoping that you can trust the default copy constructor to "do the right thing" in a non-trivial case such as this. I'm not sure why you expected the right behavior--perhaps you're hoping that memorizing rules-of-thumb such as the "rule of 3" will be a robust way to ensure that you don't shoot yourself in the foot? Certainly that would be nice (and, as pointed out in another answer, Rust goes much further than other low-level languages toward making foot-shooting much harder), but C++ simply isn't designed for "thoughtless" class design of that sort, nor should it be.
Conceptualizing constructor behavior
I'm not going to try to address the question of whether this is a "well-known problem", because I don't really know how well-characterized the problem of "sister" data and iterator-storing is. But I hope that I can convince you that, if you take the time to think about copy-constructor-behavior for every class you write that can be copied, this shouldn't be a surprising problem.
In particular, when deciding to use the default copy-constructor, you must think about what the default copy-constructor will actually do: namely, it will call the copy-constructor of each non-primitive, non-union member (i.e. members that have copy-constructors) and bitwise-copy the rest.
When copying your vector of iterators, what does std::vector's copy-constructor do? It performs a "deep copy", i.e., the data inside the vector is copied. Now, if the vector contains iterators, how does that affect the situation? Well, it's simple: the iterators are the data stored by the vector, so the iterators themselves will be copied. What does an iterator's copy-constructor do? I'm not going to actually look this up, because I don't need to know the specifics: I just need to know that iterators are like pointers in this (and other respect), and copying a pointer just copies the pointer itself, not the data pointed to. I.e., iterators and pointers do not have deep-copying by default.
Note that this is not surprising: of course iterators don't do deep-copying by default. If they did, you'd get a different, new set for each iterator being copied. And this makes even less sense than it initially appears: for instance, what would it actually mean if uni-directional iterators made deep-copies of their data? Presumably you'd get a partial copy, i.e., all the remaining data that's still "in front of" the iterator's current position, plus a new iterator pointing to the "front" of the new data structure.
Now consider that there is no way for a copy-constructor to know the context in which it's being called. For instance, consider the following code:
using iter = std::set<size_t>::iterator; // use typedef pre-C++11
std::vector<iter> foo = getIters(); // get a vector of iterators
useIters(foo); // pass vector by value
When getIters is called, the return value might be moved, but it might also be copy-constructed. The assignment to foo also invokes a copy-constructor, though this may also be elided. And unless useIters takes its argument by reference, then you've also got a copy constructor call there.
In any of these cases, would you expect the copy constructor to change which std::set is pointed to by the iterators contained by the std::vector<iter>? Of course not! So naturally std::vector's copy-constructor can't be designed to modify the iterators in that particular way, and in fact std::vector's copy-constructor is exactly what you need in most cases where it will actually be used.
However, suppose std::vector could work like this: suppose it had a special overload for "vector-of-iterators" that could re-seat the iterators, and that the compiler could somehow be "told" only to invoke this special constructor when the iterators actually need to be re-seated. (Note that the solution of "only invoke the special overload when generating a default constructor for a containing class that also contains an instance of the iterators' underlying data type" wouldn't work; what if the std::vector iterators in your case were pointing at a different standard set, and were being treated simply as a reference to data managed by some other class? Heck, how is the compiler supposed to know whether the iterators all point to the same std::set?) Ignoring this problem of how the compiler would know when to invoke this special constructor, what would the constructor code look like? Let's try it, using _Ctnr<T>::iterator as our iterator type (I'll use C++11/14isms and be a bit sloppy, but the overall point should be clear):
template <typename T, typename _Ctnr>
std::vector< _Ctnr<T>::iterator> (const std::vector< _Ctnr<T>::iterator>& rhs)
: _data{ /* ... */ } // initialize underlying data...
{
for (auto i& : rhs)
{
_data.emplace_back( /* ... */ ); // What do we put here?
}
}
Okay, so we want each new, copied iterator to be re-seated to refer to a different instance of _Ctnr<T>. But where would this information come from? Note that the copy-constructor can't take the new _Ctnr<T> as an argument: then it would no longer be a copy-constructor. And in any case, how would the compiler know which _Ctnr<T> to provide? (Note, too, that for many containers, finding the "corresponding iterator" for the new container may be non-trivial.)
Resource management with std:: containers
This isn't just an issue of the compiler not being as "smart" as it could or should be. This is an instance where you, the programmer, have a specific design in mind that requires a specific solution. In particular, as mentioned above, you have two resources, both std:: containers. And you have a relationship between them. Here we get to something that most of the other answers have stated, and which by this point should be very, very clear: related class members require special care, since C++ does not manage this coupling by default. But what I hope is also clear by this point is that you shouldn't think of the problem as arising specifically because of data-member coupling; the problem is simply that default-construction isn't magic, and the programmer must be aware of the requirements for correctly copying a class before deciding to let the implicitly-generated constructor handle copying.
The elegant solution
...And now we get to aesthetics and opinions. You seem to find it inelegant to be forced to write a copy-constructor when you don't have any raw pointers or arrays in your class that must be manually managed.
But user-defined copy constructors are elegant; allowing you to write them is C++'s elegant solution to the problem of writing correct non-trivial classes.
Admittedly, this seems like a case where the "rule of 3" doesn't quite apply, since there's a clear need to either =delete the copy-constructor or write it yourself, but there's no clear need (yet) for a user-defined destructor. But again, you can't simply program based on rules of thumb and expect everything to work correctly, especially in a low-level language such as C++; you must be aware of the details of (1) what you actually want and (2) how that can be achieved.
So, given that the coupling between your std::set and your std::vector actually creates a non-trivial problem, solving the problem by wrapping them together in a class that correctly implements (or simply deletes) the copy-constructor is actually a very elegant (and idiomatic) solution.
Explicitly defining versus deleting
You mention a potential new "rule of thumb" to follow in your coding practices: "Disable copying by default on all classes I write, unless I can explicitly prove they are correct." While this might be a safer rule of thumb (at least in this case) than the "rule of 3" (especially when your criterion for "do I need to implement the 3" is to check whether a deleter is required), my above caution against relying on rules of thumb still applies.
But I think the solution here is actually simpler than the proposed rule of thumb. You don't need to formally prove the correctness of the default method; you simply need to have a basic idea of what it would do, and what you need it to do.
Above, in my analysis of your particular case, I went into a lot of detail--for instance, I brought up the possibility of "deep-copying iterators". You don't need to go into this much detail to determine whether or not the default copy-constructor will work correctly. Instead, simply imagine what your manually-created copy constructor will look like; you should be able to tell pretty quickly how similar your imaginary explicitly-defined constructor is to the one the compiler would generate.
For example, a class Foo containing a single vector data will have a copy constructor that looks like this:
Foo::Foo(const Foo& rhs)
: data{rhs.data}
{}
Without even writing that out, you know that you can rely on the implicitly-generated one, because it's exactly the same as what you'd have written above.
Now, consider the constructor for your class Foo:
Foo::Foo(const Foo& rhs)
: set{rhs.set}
, vector{ /* somehow use both rhs.set AND rhs.vector */ } // ...????
{}
Right away, given that simply copying vector's members won't work, you can tell that the default constructor won't work. So now you need to decide whether your class needs to be copyable or not.
I have a problem which I cannot understand:
Let's Say I have a class System with several member fields, and one of them is of type unordered_map, so when I declare the class in the header file, I write at the beginning of the header #include <unordered_map>.
Now, I have two ways of declaring this field:
1.std::unordered_map<std::string,int> umap;
2.std::unordered_map<std::string,int>* p_umap;
Now in the constructor of the class, if I choose the first option, there is no need to initialize that field in the initializer list since the constructor of class System will call the default constructor for the field umap as part of constructing an instance of type class System.
If I choose the second option, I should initialize the field p_umap in the constructor (in the initialize list) with the operator new and in the destructor, to delete this dynamic allocation.
What is the difference between these two options? If you have a class that one of it's fields is of type unordered_map, how do you declare this field? As a pointer or as a variable of type unordered_map?
In a situation like the one you are describing, it seems like the first option is preferable. Most likely, in fact, the unordered map is intended to be owned by the class it is a data member of. In other words, its lifetime should not be extended beyond the lifetime of the encapsulating class, and the encapsulating class has the responsibility of creating and destroying the unordered map.
While with option 1 all this work is done automatically, with option 2 you would have to take care of it manually (and take care of correct copy-construction, copy-assignment, exception-safety, lack of memory leaks, and so on). Surely you could use smart pointers (e.g. std::unique_ptr<>) to encapsulate this responsibility into a wrapper that would take care of deleting the wrapped object when the smart pointer itself goes out of scope (this idiom is called RAII, which is an acronym for Resource Acquisition Is Initialization).
However, it seems to me like you do not really need a pointer at all here. You have an object whose lifetime is completely bounded by the lifetime of the class that contains it. In these situations, you should just not use pointers and prefer declaring the variable as:
std::unordered_map<std::string, int> umap;
Make it not a pointer until you need to make it a pointer.
Pointers are rife with user error.
For example, you forgot to mention that your class System would also need to implement
System( const Sysytem& )
and
System& operator= ( const System& )
or Bad Behavior will arise when you try to copy your object.
The difference is in how you want to be able to access umap. Pointers can allow for a bit more flexibility, but they obviously add complexity in terms of allocation (stack vs heap, destructors and such). If you use a pointer to umap, you can do some pretty convoluted stuff such as making two System's with the same umap. In the end though, go with KISS unless there's a compelling reason not to.
There is no need to define it as pointer. If you do it, you must also make sure to implement copy constructor and assignment operator, or disable them completely.
If there is no specific reason to make it a pointer (and you don't show any) just make it a normal member variable.
I have a collection (currently boost::ptr_vector) of objects (lets call this vec) that needs to be passed to a few functors. I want all of the functors to have a reference/pointer to the same vec which is essentially a cache so that each functor has the same data cache. There are three ways that I can think of doing this:
Passing a boost::ptr_vector<object>& to the constructor of Functor and having a boost::ptr_vector<object>& member in the Functor class
Passing a boost::ptr_vector<object>* to the constructor of Functor and having a boost::ptr_vector<object>* member in the Functor class
avoid the use of boost::ptr_vector and directly pass an array (object*) to the constructor
I have tried to use method 3, but have been told constantly that I should use a vector instead of a raw pointer. So, I tried method 2 but this added latency to my program due to the extra level of indirection added by the pointer. I am using method 1 at the moment, however I may need to reassign the cache during the lifetime of the functor (as the data cache may change) so this may not be an appropriate alternative.
Which I don't fully understand. I assume somewhere along the way the functor is being copied (although these are all stored in a ptr_vector themselves).
Is method 3 the best for my case? method 2, is too slow (latency is very crucial), and as for method 1, I have been advised time and again to use vectors instead.
Any advice is much appreciated
A reference in C++ can only be initialized ('bound') to a variable.
After that point, a reference can not be "reseated" (made to refer to a different variable) during it's lifetime.
This is why a default copy constructor could conceivably be generated, but never the assignment operator, since that would require the reference to be 'changed'.
My recommended approach here is to use a smart pointer instead of a reference.
std::unique_ptr (simplest, takes care of allocation/deallocation)
std::shared_ptr (more involved, allows sharing of the ownership)
In this case:
std::shared_ptr<boost::ptr_vector<object> > m_coll;
would seem to be a good fit
I was wondering if there is a way in C++ to accomplish the following:
I have a base class called ResultBase and two class that are Derived from it, Variable and Expression. I have a few methods that do work on vector<ResultBase> . I want to be able to pass in vectors of Variable and Expression into these methods. I can achieve this by creating a vector<ResultBase> and using static_cast to fill it with the members from my vector of Variable/Expression. However, once the vector has run through the methods, I want to be able to get it back as the vector of Result/Expression. I'll know for sure which one I want back. static_cast won't work here as there isn't a method to reconstruct a Variable/Expression from a ResultBase, and more importantly I wouldn't have the original properties of the Variables/Expressions
The methods modify some of the properties of the ResultBase and I need those changes to be reflected in the original vectors. (i.e. ResultBase has a property called IsLive, and one of the methods will modify this property. I want this IsLive value to be reflected in the derived class used to create the ResultBase
Whats the easiest way to accomplish this?
vector<ResultBase *> should fix your slicing problem - a vector<ResultBase> will never contain classes derived from ResultBase, but rather copies that "slice off" e.g. Expression by copying the ResultBase part of it.
See What is object slicing? for a detailed explanation of slicing.
One possibility is to change your functions that do work on vector<ResultBase> into function templates that do work on vector<T>, with T a template parameter. To be even more generic, perhaps the functions can operate on a pair of iterators instead of a particular container type.
You can then call them with a vector<Variable> or vector<Expression> instead of a vector<ResultBase>, as long as Variable and Expression are both proper substitutes for ResultBase, as a derived class should be.
Alternatively as Erik says you can use pointers to get polymorphic behavior with containers. For ease of memory management, a vector of smart pointers or a Boost ptr_vector is usually preferred to a vector of raw pointers.
There's no way to convert an instance of a derived class to base and then back to derived, while preserving its original value, for pretty much the same reason that it's not possible to convert from int to char and then back, preserving the original value. If all else fails, you could perhaps bodge something together where you use the modified ResultBase objects to somehow update the original Variable or Expression objects with any changes made by the functions.
I can't use shared_ptr in my project, no boost :(
So, I'm having a class roughly similar to the one below:
class MyClass
{
private:
std::auto_ptr<MyOtherClass> obj;
};
Now, I want to store the instances of above class in std::vector. Is it safe? I've read here that it's wrong to use std::auto_ptr with STL containers. Does it apply to my situation here?
It is not safe, bacause when container will copy MyClass instnace default copy operator will call copy for all members - and for auto_ptr member too and we will have same situation as you describe in your question ( storing auto_ptr in container )
BTW: for avoid confusion at compile time add
private:
MyClass& operator=( const MyClass& );
MyClass( const MyClass& );
compiler output error if you will try use copy operators, this can save you from hours of debug.
As Neil Butterworth said, auto_ptr is probably not the way to go.
boost::shared_ptr clearly is, but you say you can't use boost.
Let me mention that you could download boost, extract what you need for shared\ptr only using the bcp tool and use boost::shared_ptr. It would only mean a few added hpp files in your project. I believe it's the right way to go.
It is not valid to have an object that contains an auto_ptr in a standard container. You run into undefined behavior. Two common problems:
std::vector<>::resize copies its argument into each created element. The first copy will "succeed" (see below why not), but each further copy will be empty, because the element copied is also empty!
If something during reallocation throws, you can happen to have some elements copied (to a new buffer) - but the copy being thrown away - and other elements not, because push_back must not have any effects if an exception is being thrown. Thus some of your elements are now empty.
As this is all about undefined behavior it does not really matter. But even if we try to come up with this behavior based on what we think is valid, we would fail anyway. All the member functions like push_back, resize and so on have a const reference that takes an object of type T. Thus, a reference of type T const& is tried to copied into elements of the vector. But the implicitly created copy constructor/copy assignment operator looks like T(T&) - that is, it requires a non-const object to be copied from! Good implementations of the Standard library check that, and fail to compile if necessary.
Until the next C++ version, you have to live with this. The next one will support element types that are merely movable. That is, a moved object does not need to be equal to the object moved to. That will allow putting streams, transfer-of-ownership pointers and threads into containers.
See what the Standard says for this (17.4.3.6):
In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ Standard Library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation.
In particular, the effects are undefined in the following cases:
for types used as template arguments when instantiating a template component, if the operations on the type do not implement the semantics of the applicable Requirements subclause (20.1.5, 23.1, 24.1, 26.1).
I've posted a question as a follow-up
to this answer, see
Class containing auto_ptr stored in vector.
Assming your class does not have a user-defined copy constructor, then no, it is probably (see below) not safe. When your class is copied (as will happen when it is added to a vector) the copy constructor of the auto_ptr will be used. This has the weird behaviour of tranferring ownership of the thing being copied to the copy and, so the thing being copied's pointer is now null.
It is possible, though unlikely, that you actually want this behaviour, in which case an auto_ptr is safe. Assuming you do not, you should either:
add a copy constructor to manage the copying
Note this is not enough - see the follow-up question mentioned above for more info.
or:
use a smarter, possibly reference counted pointer, such as one of the boost smart pointers
Copying MyClass object will cause either call to assignment operator or copy constructor. If they are not overloaded to handle auto_ptr<> in unusual way, they will propagate the call to copy constructor (or assignment operator) to the auto_ptr<> member. This may lead to problems described in question you had linked.
The reason why it is not safe to instanciate a vector of auto_pointer is that there is an algorithm : sort(), that will do a copy of one object in your container on the stack. (sort() implements quicksort which needs a "pivot")
And therefore deleting it when going out of scpope of the sort() function.
As well any algorithm, or function of your own that are able to take your container as parameter, and copy one of its object on the stack will cause this issue as a result.
Well in your case, it is simple you must ensure your class does not behaves as an auto_ptr, or ensure you will never call such function/algorithm that can delete your underlying objects. The first solution is best, according to me :)
So your copy constructor and your affectation operator as well, should not give away property of the pointer object.
The best way to achieve that is to wrapp a boost smart pointer instead of an auto_ptr, to make your container safe when calling such function/algorithm.
By the way according to me, defining a better copy constructor/affectation operator to bypass this issue is not a good solution: I can't see a good copy constructor implementation (and affectation operator as well) that could keep safe the result of applying the sort() algorithm.
If you want to use a class that uses auto_ptr in a container, you can just provide a copy-constructor and assignment operator yourself:
class MyClass
{
private:
const std::auto_ptr<MyOtherClass> obj; // Note const here to keep the pointer from being modified.
public:
MyClass(const MyClass &other) : obj(new MyOtherClass(*other.obj)) {}
MyClass &operator=(const MyClass &other)
{
*obj = *other.obj;
return *this;
}
};
But as mentioned elsewhere, the standard lets containers make copies and assignments and assumes that the contained classes will behave in a specific manner that auto_ptr violates. By defining the methods above, you can make a class that contains an auto_ptr behave. Even if your implementation works fine with auto_ptrs, you run the risk of finding another implementation doesn't work. The standard only make guarantees of performance and observable behaviour, not implementation.
It will not work. auto_ptr doesn't count references which means at the first destructor call your pointer will be freed.
Use boost::shared_ptr instead.