C++ STL container insertion copy - c++

I was trying to write user defined object with std::vector. I read that for User Defined classes, if Copy Constructor and Assignment Operator are public then only one can insert its object in STL container. This is because of two reasons::
All STL contains always stores the copy of inserted objects, not the actual one. So, whenever we insert any element or object in container then it’s copy constructor is called to create a copy and then this copy is inserted into the container.
While insertion in std::vector it might be possible that storage relocation takes place internally due to insufficient space. In such cases assignment operator will be called on objects inside the container to copy them from one location to another. why all STL container always stores the copy of inserted objects, not the actual one? I couldn't understand the reason as to why they didn't allow the storing of the actual object. what was the disadvantage?

The standard containers in C++ allocate memory that they manage. If your program creates an object, then that object is in another memory place, so to be part of the container, a copy is made in the memory of the container.
Instead of copying, moving could have been done, but in a lot of cases, that would not be more efficient and sometimes it could even be quite inconvenient.
A good solution to avoid copying is to create the object directly in the container with the emplace-functions.
About the vector growing, because it is possible that the new vector has to be at a different memory address and the memory contains the objects, they have to be moved or copied. This answer shows how you can make the vector move upon resizing.

Related

Is std::vector trivially copyable and why?

I came across with an issue with std::vector<T>, where T is a built-in type saying that the vector is not trivially copyable.
I was wondering if it's right and am looking for the reason.
Formally, a std::vector<T> (for any T) is not trivially copyable because its copy constructor is not trivial, if only because it's user-provided (as opposed to implicitly-defined).
Practically speaking, copying a vector involves more than making a shallow copy of its data members - it requires allocating a memory buffer on the heap and copying over its contents from another vector's heap-allocated buffer.
A vector grows as data is added to it. This means that one does not need to know upfront how much space is needed to store all its data. The vector solves this problem by allocating (and reallocating) a separate storage buffer on the heap. This buffer is managed internally while providing an interface that can be though of as a variably sized array.
Now if an object is trivially-constructable, one should be able to copy/clone the object simply using memcpy(dest, &a, sizeof(a)). If one were to do this for a vector, one would have 2 vector objects pointing to the same storage buffer. This will result in horrible undefined behaviour. Copying a vector therefore requires that one duplicate the internal storage, duplicate its parameters and then set the internal pointer to point to the correct storage buffer. This requires internal knowledge of the object to do.
std::array however, has a static size set at compile time. It does not have internal pointers and can therefore be copied simply by using memcpy. It therefore is trivial to copy.

Creating a list of objects containing std::atomic

I have a list of objects stored in a list that represent chunks of read-only memory for threads to use. each chunk object has an atomic that acts as a reference count, pretty simple.
I have a problem though, std::list<Type> apparently needs a copy constructor for Type?, and having an std::atomic as a member of Type deletes the default copy constructor of the chunk object's class. I'm pretty sure a list isn't allowed to copy or move it's elements around whatsoever in memory, so why would it require that constructor?
Anywho, the question, how might I have a list of objects containing std::atomic? The atomic cannot change address, I have no interest in copying or moving it, so it seems I need to use something other than std::list?

A mutable container of immutable objects in C++

I'd like to have something equivalent to a C++ std::vector, where the underlying objects are immutable. So I can push_back() items to add them to the vector, etc. An actual std::vector maintains an array underneath that's bigger than the size of the vector, filled with default constructed objects, and when you push_back(), it does an assignment to an element in the array. My immutable objects don't have a default constructor, and assignment is a mutating operation, so that's out too.
I can do a vector<boost::optional<T>>, but that's a messy interface because I only want to put validly constructed objects into the vector, and only get those out of the vector.
I thought boost had something like this, but I couldn't find it. Does something like this exist?
Your conception of how the vector works is incorrect.
The vector uses the allocator to allocate raw memory. That raw memory does not contain default constructed objects--it's just raw memory.
When you do a push_back (for example) it then uses a placement new to construct an object into the raw memory. Likewise, when you erase an object, it will end up directly invoking its destructor to turn the object back into raw memory.
With a current (C++11 or later) implementation of std::vector, your object doesn't need to support default construction or assignment. Supporting move construction and move assignment should be sufficient. To put them to use, you'd want to use emplace_back instead of push_back though.

Memory allocation of values in a std::map

I've had some experience in C++ from school works. I've learned, among other things, that objects should be stored in a container (vector, map, etc) as pointers. The main reason being that we need the use of the new-operator, along with a copy constructor, in order to create a copy on the heap (otherwise called dynamic memory) of the object. This method also necessitates defining a destructor.
However, from what I've read since then, it seems that STL containers already store the values they contain on the heap. Thus, if I were to store my objects as values, a copy (using the copy constructor) would be made on the heap anyway, and there would be no need to define a destructor. All in all, a copy on the heap would be made anyway???
Also, if(true), then the only other reason I can think of for storing objects using pointers would be to alleviate resource needs for copying the container, as pointers are easier to copy than whole objects. However, this would require the use of std::shared_ptr instead of regular pointers, since you don't want elements in the copied container to be deleted when the original container is destroyed. This method would also alleviate the need for defining a destructor, wouldn't it?
Edit : The destructor to be defined would be for the class using the container, not for the class of the objects stored.
Edit 2 : I guess a more precise question would be : "Does it make a difference to store objects as pointers using the new-operator, as opposed to plain values, on a memory and resources used standpoint?"
The main reason to avoid storing full objects in containers (rather than pointers) is because copying or moving those objects is expensive. In that case, the recommended alternative is to store smart pointers in the container.
So...
vector<something_t> ................. Usually perfectly OK
vector<shared_ptr<something_t>> ..... Preferred if you want pointers
vector<something_t*> ................ Usually best avoided
The problem with raw pointers is that, when a raw pointer disappears, the object it points to hangs around causing memory and resource leaks - unless you've explicitly deleted it. C++ doesn't have garbage collection, and when a pointer is discarded, there's no way to know if other pointers may still be pointing to that object.
Raw pointers are a low-level tool - mostly used to write libraries such as vector and shared_ptr. Smart pointers are a high-level tool.
However, particularly with C++11 move semantics, the costs of moving items around in a vector is normally very small even for huge objects. For example, a vector<string> is fine even if all the strings are megabytes long. You mostly worry about the cost of moving objects if sizeof(classname) is big - if the object holds lots of data inside itself rather than in separate heap-allocated memory.
Even then, you don't always worry about the cost of moving objects. It doesn't matter that moving an object is expensive if you never move it. For example, a map doesn't need to move items around much. When you insert and delete items, the nodes (and contained items) stay where they are, it's just the pointers that link the nodes that change.

Removing something from a STL container without deconstructing it

Ok, I'm using C++ STL containers (currently vector<customType*>).
Now I need to remove elements from the container,
but using erase deconstructs the object, which is bad, since I'm taking it off one, and putting it onto a variable doing some processing then onto another one.
At the moment my code is quite nasty, and I'm just putting NULL in its place after I've read it, into my variable, and then putting a if (Q[ii]NULL) continue.
But this is not so great.
If you have a container of pointers (which it sounds like you do since you are assigning NULL to "erased" elements), then erasing an element from the container does not delete the pointed-to object. You are responsible for doing that yourself.
If you have a container of objects (well, non-pointer objects), then you need to copy the element out of the container before you erase it.
You can't really remove the element from the vector without destroying it. If your vector stores pointers, you can remove the pointer to the element, which won't actually destroy the element itself.
STL container operations have copy semantics. So any time you add or remove elements, the constructor or destructor will get called accordingly (assuming a non-primitive type). And if the vector gets resized in the process, all objects will be copy-constructed and the originals destructed. There's no way to avoid all this copying.
The only way to avoid the overhead is to have a vector of (smart) pointers instead of objects.