As per the document, which says that:
std::unique_ptr is commonly used to manage the lifetime of objects, including:
as the element type in move-aware containers, such as std::vector,
which hold pointers to dynamically-allocated objects (e.g. if
polymorphic behavior is desired) [emphasis mine]
How to understand it in the right way?
Some simple example may helps.
Thanks.
This statement refers to the fact that it was notoriously unsafe to use std::auto_ptr as an element in containers. std::auto_ptr is deprecated already since C++11, but before that there was no move semantics in C++, and auto_ptr was the only "smart" pointer that was really standartized.
std::auto_ptr was similar to std::unique_ptr in that it was destroying the underlying object in the destructor. In contrast to the unique pointer, auto pointer allowed copying: the ownership of the object was transferring to the destination, while the source object was losing the ownership, still pointing to the object. This behavior was unsafe in containers: while you may rely on that the container of auto pointers keeps the ownership, you may easily lose it by simple access to the element (imagine what would happen when you would access the element next time after the actual temporary owner would be destroyed).
It worth mentioning that the STL library provided by Visual Studio C++ 6.0 had a different implementation of auto_ptr: instead of transferring the ownership this "smart" pointer was transferring everything, even the pointer value itself. That meant that the source auto_ptr was becoming empty after the assignment to another "copy" of this pointer. That was safer to store the objects like that in a container, but it caused other problems anyway.
Overall, the problems with usage auto_ptr in containers was [probably] the main reasons why std::auto_ptr was deprecated in C++11.
Returning back to std::unique_ptr: it is safe to use it in containers, and the standard clearly makes an explicit statement referring to the previous problems with std::auto_ptr.
Related
The boost documentation page reads
scoped_ptr cannot be used in C++ Standard Library containers. Use shared_ptr if you need a smart pointer that can.
I'm supposing that being non-copyable would be an obstacle for scoped_ptr but since c++11, as far as some containers are concerned, we can :
Constuct in place with emplace_back etc
Move resources without copying
So what's the reason for scoped_ptr being non useable with STL containers ?
The documentation is somewhat out-of-date. Boost.ScopedPtr is an old library, and the maintainers have not cared to keep the documentation in-sync with the latest developments in C++.
In theory a scoped_ptr-like class could work (as evidenced by std::unique_ptr); but in reality, boost::scoped_ptr cannot be usefully used in many standard containers, since it has a private copy constructor and no move constructor. In particular, std::vector and std::deque require that their contents be move-constructible.
scoped_ptr can be used in node-based containers (since such containers do not require that their contents be move-constructible), if only a limited subset of the container's interface is used. Code such as the following is valid:
std::list<boost::scoped_ptr<int>> list;
list.emplace_back(new int(16));
std::map<int, boost::scoped_ptr<int>> map;
map.emplace(
std::piecewise_construct,
std::forward_as_tuple(10),
std::forward_as_tuple(new int(14)));
Even so, it is needlessly painful compared to just using std::unique_ptr (since using std::unique_ptr will allow you to use a far larger proportion of the standard container's interfaces).
As state is the doc,
It supplies a basic "resource acquisition is initialization" facility, without shared-ownership or transfer-of-ownership semantics. Both its name and enforcement of semantics (by being noncopyable) signal its intent to retain ownership solely within the current scope.
and
Q. Why doesn't scoped_ptr have a release() member?
A. When reading source code, it is valuable to be able to draw conclusions about program behavior based on the types being used. If scoped_ptr had a release() member, it would become possible to transfer ownership of the held pointer, weakening its role as a way of limiting resource lifetime to a given context.
scope_ptr exists to be safer that the deprecated auto_ptr and to represent RAII.
Now in C++11, we have std::unique_ptr to represent unique ownership.
I've read today that you should not use the STL containers for auto_ptr because of
the fact that the auto_ptr deletes it rhs value in the = operator.
So i have 2 question :
1) Does this mean that all classes that have this behavior should not be used in containers?
2) what sort of containers can you use?
1) Does this mean that all classes that have this behavior should not
be used in containers?
Yes indeed, because that is not correct copying behaviour, since the copy is not equal to the source afterwards but destroys the source. This is kind of a broken implementation of move-semantics before C++11, required for the strict unique ownership semantics of std::auto_ptr.
2) what sort of containers can you use?
The real answer is actually, that classes having this behaviour (a copy constructor/assignment destroying its source) should just not exist. And fortunately this is not needed anymore nowadays, since C++11 has proper move-semantics, which realize exactly this destructive copy but in a safe way (simply said, only when the source is really not needed anymore).
Therefore std::auto_ptr is deprecated and should not be used anymore. It has been replaced by std::unique_ptr which is movable but not copyable. But since C++11 containers rather move their elements than copy when appropriate, a std::unique_ptr can be used perfectly inside of standard containers. You just cannot copy the container or fill it with a single object which would require copies of std::unique_ptrs, but those operations should not work anyway, since they are conceptually wrong for unique ownership semantics.
And as a side note, if you actually chose std:auto_ptr for a reason, that is you want unique ownership semantics, then a std::shared_ptr (as suggested by other answers) is plain wrong since it exhibits shared ownership. std::unique_ptr is today's std::auto_ptr. Never spam std::shared_ptrs where std::unique_ptrs (or even raw pointers, but from your question I rule that option out) are appropriate.
Auto pointer has a very strict ownership: it and only it is responsible for the lifetime of the object it points at. If you copy an auto_ptr, you lose the reference to what it pointed at.
The problem is in the way STL containers do their stuff. For example, when you are adding an element, the container might expand to get more memory, which leads to copying all the values to the new memory, which, itself, leads to losing the auto_ptrs.
I think that associative containers might not copy themselves entirely when they allocate additional memory, but I'm absolutely not sure, if someone can confirm it, please post a comment, or just edit my answer. Anyway, you'd better not risk it.
Also note that Auto_ptr is deprecated since C++0x, it is advised to use unique_ptr instead. In your case, std::shared_ptr will probably do the trick, unless you really need unique ownership for those objects of yours.
Exactly.
In general, sequence container elements must be CopyConstructible and Assignable. This means that they require:
public copy constructor
public assignment operator
Asociative containers (set<> and map<>) also must provide strict weak ordering, i.e. operator < must be defined (or a dedicated comparison function).
Chapter 23.1 of C++ standard provides detailed requirements.
In our large project we have a lot class with the following typedef's:
class Foo
{
public:
typedef std::auto_ptr<Foo> Ptr;
typedef boost::shared_ptr<Foo> Ref;
...
};
...
Foo::Ref foo(new Foo);
...
doBar(foo);
...
The using of them is very convenient. But I doubt if auto_ptr is semantically close to Ptr and shared_ptr is the same as ref? Or should auto_ptr be used explicitly since it has "ownership transfer" semantics?
Thanks,
std::auto_ptr has ownership transfer semantics, but it's quite broken. If you can use boost::shared_ptr, then you should use boost::unique_ptr instead of std::auto_ptr, since it does what one would expect. It transfers ownership and makes the previous instance invalid, which std::auto_ptr doesn't.
Even better, if you can use C++11, then swap to std::unique_ptr and std::shared_ptr.
You shouldn't use std::auto_ptr, its deprecated and I consider it dangerous, even more so when you hide it behind such a generic typedef as Ptr.
I don't think it makes any sense to called shared_ptrRef, in this case it is more Ptr than auto_ptr.
EDIT: I consider it dangerous because you can easily misuse it, even when you fully understand its workings, you can accidentally misuse it, especially when hiding it behind a typedef. A good class should be easy to use right and should be difficult to misuse. Especially with the advent of unique_ptr I can't see any useful scenario for auto_ptr.
I believe the order is just a nomenclature which someone used.
It probably should have been, ref for auto_ptr and ptr for shared_ptr, because:
References are immutable and hence cannot be made to refer to other object. auto_ptr has a similar(albeit remotely similar) semantics, transfer of ownership which means you would probably not want to assign a auto_ptr for the non-intuitive behavior it shows. The assigned object gains ownership while the object being assigned loses ownership.
On the Other hand shared_ptr has an reference counting mechanism which is similar(again remotely) to multiple pointers which can point to the same object. The ownership of the pointer rests with the shared_ptr itself and it gets deallocated as soon as there are no pointer instances referring to it.
A lot depends on what they are being used for. And in the case of
Ref, what people understand by it. In pre-standard days, I would
often use a typedef to Ptr for my (invasive) reference counted
pointer; the presence of such a typedef was, in fact, an indication that
the type supported reference counting, and that it should always be
dynamically allocated.
Both std::auto_ptr and boost::shared_ptr have very special
semantics. I'd tend not to use typedefs for them, both because of the
special semantics, and because (unlike the case of my invasive reference
counted pointer) they are totally independent of the type pointed to.
For any given type, you can use them or not, as the program logic
requires. (Because of its particular semantics, I find a fair number of
uses for std::auto_ptr. I tend to avoid boost::shared_ptr, however;
it's rather dangerous.)
auto_ptr is deprecated in C++11. You might want to stop using it and just use the shared_ptr. For shared_ptr, there is no ownership transfer on assignment, the number of references to the object is counted and the object is destroyed when the last pointer is destroyed.
After reading timdays answer to this question I am curious about the difference between boost::ptr_container and a std::vector<shared_ptr>. I was under the impression that a boost::ptr_container had ownership over the pointers given to it, and upon release would call the destructors of all the pointers it contained regardless of other references to its inhabitants. Which is contrary to the purpose of a std::vector<shared_ptr>, which after release would only release the pointers themselves if the ref count was 0?
If this is the case (I assume it isn't), why would even the Boost documentation example compare the two as though they are similar in purpose, and why would timday's answer propose a boost::ptr_container when it is very different to the purpose of a std::vector<shared_ptr>.
You are right, the two are widely different.
The first difference, as you noticed, is the ownership semantics. The ownership of items in a Pointer Container is NOT shared. In this regard, a boost::ptr_vector<T> is much closer to a std::vector<std::unique_ptr<T>>.
But this is not the only difference!
unless explicitly stated in the type, a Pointer Container will not contain any null pointer
a Pointer Container has deep copy semantics (using the new_clone method), and can only be copied if the object held is copyable
a Pointer Container has deep const semantics, that is if the container is const then one cannot mutate one of its element.
As for why #timday felt compelled to mention Boost Pointer Container, I think it's because he wanted to broaden the question somewhat. Boost Pointer Container are very much like Smart Pointers that could hold multiple objects, and provide a nicer syntax that containers of pointers in general.
Regarding his comparison to a std::vector< boost::shared_ptr<T> > I think it is simply because this is the traditional way of implementing a vector of pointers in the absence of move semantics (no unique_ptr) since auto_ptr cannot be used in STL container. People just don't know about Pointer Containers most of the time...
There are situations where both can be applied: say a bunch of functions act as clients of container, taking pointers to polymorphic objects out and doing operations on them. If the container outlives all the functions, it can be replaced by a pointer container.
Timday answered the question "What is the difference between the following set of pointer[s]" by pointing out an omission in the list.
I am learning about smart pointers (std::auto_ptr) and just read here and here that smart pointers (std::auto_ptr) should not be put in containers (i.e. std::vector) because even most compilers won't complain and it might seem correct. There is no rule that says smart pointers won't be copied internally (by vector class for example) and transfer its ownership, then the pointer will become NULL. In the end, everything will be screwed up.
In reality, how often does this happen?
Sometimes I have vectors of pointers and if in the future I decide I want to have a vector of smart pointers what would my options?
I am aware of C++0x and Boost libraries, but for now, I would prefer to stick to a STL approach.
Yes, you really can't use std::auto_ptr with standard containers. std::auto_ptr copies aren't equivalent, and because standard containers (and algorithms) are allowed to copy their elements at will this screws things up. That is, the operation of copying a std::auto_ptr has a meaning other than a mere copy of an object: it means transferring an ownership.
Your options are:
Use the Boost Smart Pointers library. This is arguably your best option.
Use primitive pointers. This is fast and safe, so long as you manage the pointers properly. At times this can be complex or difficult. For example, you'll have to cope with (avoid) double-delete issues on your own.
Use your own reference-counting smart pointer. That'd be silly; use a Boost Smart Pointer.
The problem you are referring to concerns auto_ptr since it moves ownership on copy. shared_ptr and unique_ptr work just fine with containers.
Any type that you use with a standard container template must conform with the requirements for that container. In particular, the type must satisfy the requirements for CopyConstructible and Assignable types.
Many smart pointers do satisfy these requirements and may be used with standard containers but std::auto_ptr is not one of them because copies of std::auto_ptr are not equivalent to the source that they were created or assigned from.
Although some implementations of standard container may work with auto_ptr in some situations it is dangerous to rely on such implementation details.
theoretically you can use std::auto_ptr with STL containers if you completely understand their internal implementation and don't do anything that can lose auto_ptr ownership, but practically it's much more safe to use containers with raw ptrs.
"In reality, how often does this happen?" - is very dangerous question by itself. first of all, STL - it's not a single standard implementation, there're many. Each one can implement containers in different ways, so your highly tuned code to avoid all "auto_ptr in containers" mines can burst switching to another STL implementation. Also, your code maintenance will be highly complicated, any correctly looking change to your code can break your program. how can you remember that or force others maintainers to remember? putting warnings in any place where such changes can occur? impossible.
so, conclusion: it's just a bad idea that brings nothing but headache
For classes that have an auto ptr data member, I always have a clone method that returns a new auto ptr. I then implement an assignment method and copy constructor that call the clone method (and never the default assignment operator of auto ptr). This way you can safely use the class in STL containers.