I have a case where I wish to store a list of resources in a std::vector. As I see it, my options are as follows:
Give my resource a default constructor
Store them as heap objects (and wrap them in a shared pointer)
Option 1 makes it possible to construct invalid resources and option 2 forces me to use the heap.
Am I missing any options here?
You don't need a default constructor to have a vector of instances.
The only limitation is you can't use vector::resize with the default argument when the class has no default constructor.
vec.resize(20); // requires default constructor
but you can give vector::resize a default object:
std::vector<foo> vec;
vec.resize(20, foo(10)); // give a sample object since foo has not default constructor
You may store objects with non trivial constuctor in vector. The the objects store in stl containers should have assignment semantic (copy constructor and assign operator).
A third option would be to use Boost.PointerContainer. However, your objects will still be individually allocated on the heap. As Johann has commented, std::vector already makes use of the heap to store objects (contiguously), so there's no way to completely avoid the heap.
It often doesn't make sense to allow resources (such as mutexes, I/O streams, etc) to have copy semantics. So they must be rendered non-copyable by making the copy constructor and assignment operator private. Unfortunately, the non-copyable restriction makes it impossible to store resources directly as values inside STL containers. One must therefore resort to either Boost.PointerContainer or containers of smart pointers. The Motivation section of the Boost.PointerContainer documentation explains why you'd prefer to use one over the other.
Related
I don't understand why don't they have a copy constructor which makes a real multiple of the original.
As we know the main problem of the default copy constructor is, that it performs a shallow copy. So that if there is a pointer it would only copy it's address but why doesn't it dereference the pointer a copies the content?
The main problem arises when having a dinamic allocation of memory . So that one can mistakenly delete it while having a pointer pointing to it, that's why we make our own copy constructors and do not use the default one.
But I can't get it, why doesn't CPP do it? Why doesn't it copy the content
As we know the main problem of the default copy constructor is, that it performs a shallow copy.
We don't know that.
that's why we make our own copy constructors and do not use the default one.
In C++ you should almost never write your own copy constructor (the rule of zero).
The main problem arises when having a dinamic allocation of memory . So that one can mistakenly delete it while having a pointer pointing to it
It's a non-problem. Why? Because in C++ we use the concept of RAII and we have tools in the standard library that solved all of the problems you see. In C++ you should never have to write explicit new and you should never have a raw pointer that is a owner. Use standard containers (e.g. std::vector) and smart pointers e.g. (std::unique_ptr).
I don't understand why don't they have a copy constructor which makes a real multiple of the original
Because the compiler doesn't know what the copy-semantics of the object should be. That only the writer of the class knows. You can't know what the semantics of the pointer are. Is is a pointer that uniquely owns the memory resource? If so, was it acquired with malloc, new, new[], or with something else? Does it share its ownership of the memory? Or is it simply pointing to an object it doesn't own? Since you cannot know any of this from the declaration/definition of a class, a compiler simply cannot implement "deep copy" automatically with raw pointers.
Except it does. It does implement deep copy by default, or shallow copy by default, or a combination of them. And it does so correctly. Remember when I told you to not use raw pointers for ownership? Use the appropriate abstractions (containers, smart pointers) and the default copy ctor will do exactly what it needs to do.
As we know the main problem of the default copy constructor is, that it performs a shallow copy.
Shallow copying is not a problem in general. It's only a problem if you want to make a deep copy, have a referential member, and assume the implicit copy constructor to do what you want.
Shallow copying is often useful and typically intentional.
but why doesn't it dereference the pointer a copies the content?
Because where would the copy constructor store the copied object? Where should the pointer member point to?
The compiler cannot read your mind and cannot know whether you want to allocate memory, or how to allocate memory. If the compiler did allocate memory in an implicit function, then who would be responsible for its deletion? If the compiler deleted any pointers implicitly, that would be highly surprising when you intended to have non-owning pointers to something that must not be deleted.
why can't the programmer be responsible for it?
Memory management is difficult enough as it is. At the moment it is at least manageable by following the simple rule: You delete everything that you new. If we introduce implicit allocations and impose the responsibility on the programmer to know of the existence of these implicit allocations, our job would become much harder.
Furthermore, a pointer can have an invalid value. In such cases indirecting through it would have undefined behaviour. And it is impossible to inspect the pointer to find out whether it is invalid. This would make the suggested implicit "deep copying" highly error prone.
Shallow implicit copying is the only sensible choice in a language that has manual memory management. Even in garbage collected languages this is generally the better choice.
that's why we make our own copy constructors and do not use the default one.
We rarely write user declared copy constructors (outside of beginner courses). Those are mostly needed for classes whose sole purpose is to manage memory (or other resources) such as smart pointers. And we rarely need to write those, since the standard library offers the most general smart pointers and data structures out of the box.
we should create our own copy constructor once we have a dynamic memory inside the class
Indeed, if your class manages dynamic memory, then it will need a custom copy constructor. But the typical solution is to not manage dynamic memory inside your class. See the paragraph above. Keep any and all memory allocations and other dynamic resources in a smart pointer or a container.
The compiler has no way of knowing the meaning of the pointers it is supposed to "deep copy".
For example, does a float pointer point to a single float or to a C-style float array? If it is an array, what is the length of the array that it should copy? Please note that I am not talking about C++ style arrays (i.e. std::array).
If you want "deep copying" to be handled automatically, you can use container classes for data members that should be copied.
std::copy is a more general approach since it can handle containers with differing value types (e.g. copy from std::vector<float> to std::vector::<double>). But when the value type is the same for both containers, does it matter whether I use the copy constructor instead of std::copy?
Don't worry about performance, they should all be super close. Instead:
If you're creating a new container that's a copy, use the copy constructor or two-iterator constructor (if different element types).
If you're replacing (assigning) an existing container, use the appropriate assignment operator or assign member.
If you're replacing a subset of elements, use std::copy.
By accurately representing what you're trying to do, you give the compiler the most possible information to optimize its code (for example constructing directly from an existing container it can pre-allocate exactly the right about of memory).
One potentially important difference is when you have a situation where you are able to invoke the move constructor rather than the copy constructor (e.g. when the object you are copy constructing from is an rvalue, such as the return value of a function). If you have such a situation, you definitely want to make sure you take advantage of it by move constructing or move assigning rather than using std::copy.
Basically this is just another reason to follow Mark B's advice.
I am writing a class which uses the stl class map as a member. I have no pointers in the class. Do I need to write a custom copy constructor or will the default copy constructor work fine?
After reading the answers I am adding some more information. I have static const variables but those are not initialized during construction. I have no reference members. Everything else is a 64 bit integer. I also have a map iterator as a member in the class.
The default copy constructor will always work (it just calls the copy constructors of all the class members).
Generally speaking, the only time you may have an issue is when you are using members that carry non-trivial construction/destruction (like objects that manage a global resource such as file descriptors for files/kernel services and pointers for memory) that would be (and need to be) cleaned up by the destructor and reallocated by the copy constructor.
I know of some optimizations that can make the copy constructor faster if you implement it, but they aren't really necessary.
Pointer members aren't the only things that would cause problems here. There are several factors that may require you to have a custom copy constructor, including but not limited to:
Reference members, as they require explicit initialization
const member variables, same reason
Any member variables of types that do not provide copy constructors
There is a way in C++ to prohibit copy of an object of particular type. Well written libraries including STL only allow types to be copy constructable if it is safe and does make sense for that type. So if you can copy it (compiler does not generate errors), then it is safe. It is a good practice to follow this in your own program, even if it is not so big.
The default copy constructor will do fine.
I'm trying to figure out when to use move semantics and when to use a copy constructor and assignment operator as a rule of thumb. The type of pointer you use (if any) in your class seems to be affected by this answer, so I have included this.
No pointers - Based on this answer, if you have a POD class with primitive types like int and string, you don't need to write custom move or copy constructors and operators.
unique-ptr - Based on this answer, when using move semantics, then unique_ptr is a better fit over shared_ptr as there can only be one unique_ptr to the resource.
shared_ptr - Equally, if using copy semantics, shared_ptr seems the way to go. There can be multiple copies of the object, so having a shared pointer to the resource makes sense to me. However, unique_ptr is generally preferred to shared_ptr so avoid this option if you can.
But:
When should I use move semantics?
When should I use copy semantics?
Should I ever use both?
Should I ever use none and rely on the default copy constructor and assignment operator?
As the name indicates, use unique_ptr when there must exist exactly one owner to a resource. The copy constructor of unique_ptr is disabled, which means it is impossible for two instances of it to exist. However, it is movable... Which is fine, since that allows transfer of ownership.
Also as the name indicates, shared_ptr represents shared ownership of a resource. However, there is also another difference between the two smart pointers: The Deleter of a unique_ptr is part of its type signature, but it is not part of the type signature of shared_ptr. That is because shared_ptr uses "type erasure" to "erase the type" of the deleter. Also note that shared_ptr can also be moved to transfer ownership (like unique_ptr.)
When should I use move semantics?
Although shared_ptr can be copied, you may want to move them anyways when you are making a transfer of ownership (as opposed to creating a new reference). You're obligated to use move semantics for unique_ptr, since ownership must be unique.
When should I use copy semantics?
In the case of smart pointers, you should use copying to increase the reference count of shared_ptrs. (If you're unfamiliar with the concept of a reference count, research reference counted garbage collection.)
Should I ever use both?
Yes. As mentioned above, shared_ptr can be both copied and moved. Copying denotes incrementing the reference count, while moving only indicates a transfer of ownership (the reference count stays the same.)
Should I ever use none and rely on the default copy constructor and assignment operator?
When you want to make a member-by-member copy of an object.
When should I use move semantics?
I presume by this you mean, "When should I give my class a move constructor?" The answer is whenever moving objects of this type is useful and the default move constructor doesn't do the job correctly. Moving is useful when there is some benefit to transferring resources from one object to another. For example, moving is useful to std::string because it allows objects to be copied from temporaries without having to reallocate and copy their internal resources and instead by simply moving the resource from one to the other. Many types would benefit from this. On the other hand, moving is useful to std::unique_ptr because it is the only way to pass a std::unique_ptr around by value without violating its "unique ownership".
When should I use copy semantics?
Again, I presume by this you mean, "When should I give my class a copy constructor?" Whenever you need to be able to make copies of an object, where internal resources are copied between them, and the default copy constructor doesn't do the job correctly. Copying is useful for almost any type, except those like std::unique_ptr that must enforce unique ownership over an internal resource.
Should I ever use both?
Your classes should provide both copy and move semantics most of the time. The most common classes should be both copyable and moveable. Being copyable provides the standard semantics of passing around an object by value. Being moveable allows the optimisation that can be gained when passing around a temporary object by value. Whether this means having to provide a copy or move constructor depends on whether the default constructors do the appropriate things.
Should I ever use none and rely on the default copy constructor and assignment operator?
The default copy and move constructors just do a copy or move of each member of the class respectively. If this behaviour is appropriate for copying and moving your class, that's great. Most of the time, this should be good enough. For example, if I have a class that contains a std::string, the default copy constructor will copy the string over, and the default move constructor will move the string's resources to the new object - both do the appropriate job. If your class contains a std::unique_ptr, copying will simply not work, and your class will only be moveable. That may be what you want, or you may want to implement a copy constructor that performs a deep copy of the resource. The most important case in which you should implement copy/move constructors is when your class performs resource management itself (using new and delete, for example). If that's the case, the default constructors will almost never be doing a good job of managing those resources.
Everything here applies similarly to the assignment operator.
Two instances of this C++ object exist.
my_type
{
public:
std::vector<unsigned short> a;
}
One where the std::vector is empty and the other where it contains 50 elements.
Which instance copies most quickly or do they copy in the same time?
When a std::vector is copied all of it's elements are also copied - so the time taken should be proportional to vector.size().
In c++0x so called move semantics are introduced, allowing a move constructor and move assignment operator to be defined for types. These are defined for standard library containers (such as std::vector) and should allow for vector's to be moved in O(1) time. If you're worried about performance, maybe you could re-cast your operations to make use of these new features.
EDIT: Based on the linked question, if you're worried about the extra copies potentially done when calling vector::push_back you have a few options:
In c++0x use the new vector::emplace_back instead. This allows for your objects to be constructed in-place in the container.
In c++0x use move semantics, via something like vector.push_back(std::move(object_to_push)). For POD types this will still do more copying than the emplace_back option.
Store a container of pointers to objects rather than objects themselves. The only thing that will get copied by the container in this case is the pointer itself - which is cheap. You potentially want to use some variant of smart pointers with this option.
Hope this helps.