custom allocator using move for vector of thread - c++

I'm currently learning about concurrency in C++ and came across using a vector of threads, which I believe will be possible in C++0x. However, my current compiler doesn't appear to have an implementation of move-aware containers and so I get errors generated because std::thread::thread(const std::thread&) is deleted, ie I can only use the move constructor/move assignment with std::thread.
Am I correct in thinking I could circumvent this issue by writing a custom allocator using
void MyAllocator::construct (pointer p, reference val)
/* should be non-const reference to val because using move constructor? */
{
new ((void*)p) T (std::move(val));
}
rather than
void allocator::construct (pointer p, const_reference val)
{
new ((void*)p) T (val);
}
? Or some other variation on this theme (possibly using an overload of MyAllocator::construct).
NB: This is mainly intended to be a short-term educational exercise and well enough performing work around to play around with threads in containers. I'd only be using MyAllocator in this context. However, please also point me at any libraries that may have this implemented so I can have a poke around the source.

If your compiler doesn't provide a move-aware std::vector then you'll have to write your own specialization of std::vector<std::thread> rather than just provide a custom allocator. The whole C++03 vector interface relies on copying: push_back() copies elements in; resize() initializes the empty elements with a copy of the element passed as the second parameter (even if that is the default value of T()); resize(), reserve(), insert(), erase() and push_back() will copy elements if the vector needs reallocating, or elements otherwise need moving around, and so forth.
This is such a common problem that I've included such a specialization with my (commercial) just::thread implementation of std::thread.

The easiest way to circumvent the problem would be to allocate the threads on the heap and manipulate pointers to them.
Check the Boost Pointer Container library: boost::ptr_vector<std::thread> seems to me what you are looking for.

The requirement that std containers only take copyable objects has more to do with the C++03 container interfaces than it does with the allocator implementation.
For example
vector<T> b(100);
vector<T> a;
a=b;
assert(a==b);
The standard assures us a==b is true. However, if T were not copyable, then in the best case a=b will not compile, in the worst a=b is undefined. Furthermore,
a.push_back(T());
may cause a to allocate new space, and under the hood there are copies made to the new underlying storage from the old.
Furthermore, there is nothing in the C++03 standard that says an implementation actually has to call allocator.construct, and in fact many (gcc for example) do not.
The C++0x standard adds new member functions to the container interface for moveable types, and clarifies how things like operator= behave in their presence.
See www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2486.pdf

Related

Elegant avoiding of value-initialization of vector elements in future C++?

When elements are default-inserted into an instance of std::vector<T>, they are value-initialized by default. I often work with multi-threaded high-performance codes, where such value-initialization might for large arrays represent an unacceptable sequential bottleneck.
The typical approach based on reserve() and push_back()/emplace_back() is of no use if in concurrent codes. I usually end up with one of the following options:
definition of an empty default constructor for T,
definition and usage of a custom allocator with empty construct() member function.
However, both solutions are far from being elegant and also have drawbacks. The former cannot be used for T being a POD type, such as double. The latter requires a given implementation of the C++ Standard Library to supoort the relatively new DefaultInsertable concept. Moreover, definition of a custom allocator is quite tedious.
Is there any chance that in the future of C++ there will be some straightforward way how to "turn off" this default-insertion/value-initialization?
UPDATE
Mayebe, I should've asked simply if it will be possible to avoid zero-initialization of default-inserted elements of a vector for arithmetic types.
Vector is poorly suited to your needs. It supports resizing and accidental copy, neither of which make sense in a multi-threaded environment.
Write a simple container:
template<class T,class Storage=std::aligned_storage_t<sizeof(T),alignof(T)>{
struct buffer{
static_assert(std::is_pod<T)::value, "pod only");
std::size_t count;
std::unique_ptr<Storage[]> storage;
};
Populate it with container-esque begin/end/front/size/[]/empty etc.
Make it move only.
Use rule of zero (with =default).
Give it a explicit buffer(std::size_t) ctor that creates its content uninitialized.
Mix in some span/array_view types, and this should be suitable for your needs.
Maybe have emplace(size_t,Args&&) which does placement new for you with {}.

Is C++'s default copy-constructor inherently unsafe? Are iterators fundamentally unsafe too?

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.

auto_ptr vs unique_ptr in containers & algorithms

I understand auto_ptr has screwed up copy semantics and therefore is not safe for use in containers since copying one auto_ptr to another will make the source = NULL pointer (isn't this like move semantics anyway??). But then again, unique_ptr cannot be copied at all and can only transfer ownership. So, how is unique_ptr usable in containers and algorithms that need to use copy operations to copy and re-arrange elements?
There is an in-depth explanation of why auto_ptr is dangerous, while unique_ptr is not:
N1856 : Why deprecate auto_ptr?
The main argument is that in generic code, something that has the syntax of a copy, should be a copy, not a move:
template <class It>
void sort(It first, It last)
{
// ...
value_type pivot_element = *mid_point;
// ...
}
In the above example, the generic code is highly likely to have logic that demands that pivot_element and *mid_point be equivalent after the copy construction shown. This may or may not be generic code in the std::lib. It might be generic code you have written.
When value_type turns out to be a std::auto_ptr<T>, then the above code compiles, but the assumption that pivot_element == *mid_point fails. A run-time error follows.
When value_type turns out to be a std::unique_ptr<T>, then the above code fails at compile-time (because you can't copy a std::unique_ptr<T>). Thus use of std::unique_ptr<T> in preference to std::auto_ptr<T> effectively turns run time errors into compile-time errors.
Now it is also true that within the std::lib, algorithms such as sort have been respecified such that they are not allowed to copy value_type. So it actually is safe to sort a sequence of auto_ptr<T> now (using std::sort). However std::unique_ptr<T> completely replaces the functionality of auto_ptr<T>, and auto_ptr<T> is still dangerous to use in generic code that does use copying (unique_ptr<T> fails to compile when used in such generic code).
So unique_ptr is safer to use than auto_ptr because it refuses to compile when used with generic code that copies.
They don't need to use copy operations anymore in the vast majority of cases. Move-only types like unique_ptr are first-class citizens. That's why move semantics is such a great improvement for both performance and correctness.

Making use of allocators in a custom container class

I'm developing a container-like class and I would like to make use of the standard allocator infrastructure much like the standard containers. On the net I find a lot of material about how to use the std::allocator class alone, or how to define a custom allocator for standard containers, but the material about how to make generically use of an standard conforming allocator is very rare, in particular in the context of C++11, where things seem to be much easier from the point of view of who writes a custom allocator, but more complex from the container's point of view.
So my question is about how to correctly make use of a standard conforming allocator in the most generic way, specifically:
First of all, when should I design a custom container in this way? Is there a sensible performance overhead (including missing optimization opportunities) in using the default allocator instead of plain new/delete?
Do I have to explicitly call contained objects' destructors?
How do I discriminate between stateful and stateless allocators?
How to handle stateful allocators?
When (if ever) are two instances interchangeable (when can I destroy with one instance the memory allocated with another one)?
They have to be copied when the container is copied?
They can/have to be moved when the container is moved?
In the container's move constructor and move assignment operator, when can I move the pointer to allocated memory, and when do I have to allocate different memory and move the elements instead?
Are there issues about exception safety in this context?
I'm specifically interested in an answer about the C++11 world (does it change anything in C++14?)
In all answers below, I'm assuming you want to follow the rules for C++11 std-defined containers. The standard does not require you to write your custom containers this way.
First of all, when should I design a custom container in this way? Is there a sensible performance overhead (including missing
optimization opportunities) in using the default allocator instead of
plain new/delete?
One of the most common and effective uses for custom allocators is to have it allocate off of the stack, for performance reasons. If your custom container can not accept such an allocator, then your clients will not be able to perform such an optimization.
Do I have to explicitly call contained objects' destructors?
You have to explicitly call allocator_traits<allocator_type>::destroy(alloc, ptr), which in turn will either directly call the value_type's destructor, or will call the destroy member of the allocator_type.
How do I discriminate between stateful and stateless allocators?
I would not bother. Just assume the allocator is stateful.
How to handle stateful allocators?
Follow the rules laid out in C++11 very carefully. Especially those for allocator-aware containers specified in [container.requirements.general]. The rules are too numerous to list here. However I'm happy to answer specific questions on any of those rules. But step one is get a copy of the standard, and read it, at least the container requirements sections. I recommend the latest C++14 working draft for this purpose.
When (if ever) are two instances interchangeable (when can I destroy with one instance the memory allocated with another one)?
If two allocators compare equal, then either can deallocate pointers allocated from the other. Copies (either by copy construction or copy assignment) are required to compare equal.
They have to be copied when the container is copied?
Search the standard for propagate_on and select_on_container_copy_construction for the nitty gritty details. The nutshell answer is "it depends."
They can/have to be moved when the container is moved?
Have to be for move construction. Move assignment depends on propagate_on_container_move_assignment.
In the container's move constructor and move assignment operator, when can I move the pointer to allocated memory, and when do I have to allocate different memory
and move the elements instead?
The newly move constructed container should have gotten its allocator by move constructing the rhs's allocator. These two allocators are required to compare equal. So you can transfer memory ownership for all allocated memory for which your container has a valid state for that pointer being nullptr in the rhs.
The move assignment operator is arguably the most complicated: The behavior depends on propagate_on_container_move_assignment and whether or not the two allocators compare equal. A more complete description is below in my "allocator cheat sheet."
Are there issues about exception safety in this context?
Yes, tons. [allocator.requirements] lists the allocator requirements, which the container can depend on. This includes which operations can and can not throw.
You will also need to deal with the possibility that the allocator's pointer is not actually a value_type*. [allocator.requirements] is also the place to look for these details.
Good luck. This is not a beginner project. If you have more specific questions, post them to SO. To get started, go straight to the standard. I am not aware of any other authoritative source on the subject.
Here is a cheat-sheet I made for myself which describes allocator behavior, and the container's special members. It is written in English, not standard-eze. If you find any discrepancies between my cheat sheet, and the C++14 working draft, trust the working draft. One known discrepancy is that I've added noexcept specs in ways the standard has not.
Allocator behavior:
C() noexcept(is_nothrow_default_constructible<allocator_type>::value);
C(const C& c);
Gets allocator from alloc_traits::select_on_container_copy_construction(c).
C(const C& c, const allocator_type& a);
Gets allocator from a.
C(C&& c)
noexcept(is_nothrow_move_constructible<allocator_type>::value && ...);
Gets allocator from move(c.get_allocator()), transfers resources.
C(C&& c, const allocator_type& a);
Gets allocator from a. Transfers resources if a == c.get_allocator().
Move constructs from each c[i] if a != c.get_allocator().
C& operator=(const C& c);
If alloc_traits::propagate_on_container_copy_assignment::value is true,
copy assigns allocators. In this case, if allocators are not equal prior
to assignment, dumps all resources from *this.
C& operator=(C&& c)
noexcept(
allocator_type::propagate_on_container_move_assignment::value &&
is_nothrow_move_assignable<allocator_type>::value);
If alloc_traits::propagate_on_container_move_assignment::value is true,
dumps resources, move assigns allocators, and transfers resources from c.
If alloc_traits::propagate_on_container_move_assignment::value is false
and get_allocator() == c.get_allocator(), dumps resources, and transfers
resources from c.
If alloc_traits::propagate_on_container_move_assignment::value is false
and get_allocator() != c.get_allocator(), move assigns each c[i].
void swap(C& c)
noexcept(!allocator_type::propagate_on_container_swap::value ||
__is_nothrow_swappable<allocator_type>::value);
If alloc_traits::propagate_on_container_swap::value is true, swaps
allocators. Regardless, swaps resources. Undefined behavior if the
allocators are unequal and propagate_on_container_swap::value is false.

Is it safe to store objects of a class which has an std::auto_ptr as its member variable in std::vector?

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.