Creating a list of objects containing std::atomic - c++

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?

Related

What does it mean in C++ "It does not own the underlying data, and so is cheap to copy or assign"

I'm reading about mutable_buffer and it says
The mutable_buffer class provides a safe representation of a buffer
that can be modified. It does not own the underlying data, and so is
cheap to copy or assign.
By copy I think it mean copying data using memcpy. What does assign mean?
Also if I have a pointer to a data, can't I simply make mutable_buffer point to this data instead of do mine? Of course, if the sizes of both are consistent.
If you look at more context you can see that the boost buffers are constructed from existing data aggregates like arrays, std::arrays, boost::arrays or std::vectors. These are the owners of the data, meaning they are responsible for allocation and deletion.
The mutable_buffer class, by contrast, just points to the data provided by one of the mentioned containers, does not acquire it when it is created and and does not delete it when it is destroyed; this is what's meant with "it does not own the data".
Because it consists just of a pointer and an integral size and could not care less about the data it points to it is cheap to create, copy, assign and destroy. (But obviously care must be taken that the data pointed to is still valid — that's the difference to e.g. a std::vector which takes automagically care of that no matter when and how often often you copy, create and destroy it. The downside is that copying a vector copies all the data.)

C++ STL container insertion copy

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.

Stop destructor from calling when returning stack variable

I have a class List which allocates memory automatically to store a list of items.
It has a destructor which deallocates this memory:
List::~List()
{
free(memory);
}
This means, if I create a new list, I can use delete to call the destructor and free the memory.
The destructor will also be called once the variable is out of scope which is ALMOST always what I want. e.g:
int func()
{
List list;
list.push(...);
...
return 47;
}
However, what if I want to return that list?
List func()
{
List list;
return list;
}
I am alright with the list being copied because it's returned by value, and doesn't have much data to copy (only a few ints, and a pointer).
However, the memory that the list allocated and has a pointer to, contains a LOT of data.
Since I am returning the list, the list is being copied along with the pointer to this data.
Since the list is now out of scope, the destructor is called, which frees up the pointer to that data, even though the copy also has the pointer.
How do I prevent this destructor from being called?
1) There is probably a solution by creating a copy constructor, however, I don't want to do this because then all the data at that pointer will likely have to be copied which is a waste of time and temporarily requires double the memory to be allocated.
2) I know I could just create a pointer List* list and return that, but I want to avoid the necessity of allocating new memory for that list if possible, and also want to avoid wasting more memory for a pointer (8 bytes or something).
Thanks in advance,
David.
Assuming you’re using C++11 or later, you just create a move constructor which leaves the old list empty.
In order to avoid similar problems, you also need to delete the copy constructor, or actually write it so your class can be copied (don’t worry; in most cases, including the one you were worried about with returning from a function, the compiler will use the move constructor or get rid of the copy/move entirely, especially after C++17).
This is greatly simplified by storing the pointers as unique_ptr, which will help make sure you don’t make a mistake, and will mean you don’t need to explicitly write the copy or move constructors.
If you’re stuck on pre-C++11, you can’t do this, at least not without a small storage-space penalty. You’d need to use a reference-counting pointer like boost::shared_ptr (a version was added to the standard library with C++11, but it sounds like you would rather move-only semantics), which will only free the memory when it’s the last one one left referencing that memory. This makes copying, creating, and destroying lists slightly slower (since it needs to check/update the reference counter), and it takes some space to store the count, but these costs are relatively small compared to those of actually copying the list’s contents.
Note that in this case two copies always point to actually the same list. If you update one “copy”, the other also gets updated. This is usually not the behavior that users of your class would expect in C++.

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.

Safely moving a C++ object

I’ve heard some words of warning against shipping an object to another memory location via memcpy, but I don’t know the specific reasons. Unless its contained members do tricky things that depend on memory location, this should be perfectly safe … or not?
EDIT: The contemplated use case is a data structure like a vector, which stores objects (not pointers to objects) in a continuous chunk of memory (i.e. an array). To insert a new object at the n-th position, all objects starting at position n and beyond will need to be moved to make room for the object to be inserted.
One primary reason why you should not do this is destructors. When you memcpy a C++ object to another location in memory, you will end up with 2 versions of the object in memory for which only 1 constructor has been run. This will destroy the resource freeing logic of pretty much every single C++ class out there.
It's not allowed by the language specification. It is undefined behavior. That is, ultimately, what's wrong with it. In practice, it tends to mess with virtual function calls, and it means the destructor will be run twice (and more often than the constructors), member objects are shallow copied (so if, for example, if you try this stunt with a std::vector, it blows up, as multiple objects end up pointing to the same internal array.)
The exception is POD types. They don't have (copy) constructors, destructors, virtual functions, base classes or anything else that might cause this to break, so with those, you're allowed to use memcpy to copy them.
For the sake of discussion, I assume you mean moving to mean that the original object "dropped" (is no longer used, didn't have it's destructor run) rather than have two copies (which would lead to a lot more problems, reference counts being off, etc). I generally refer to the property of being able to do this being bitwise movable.
In the code bases I work on, the majority of objects are bitwise movable, as they don't store self references. However, some data structures aren't bitwise movable (I believe that gcc's std::set wasn't bitwise movable; other examples would be linked list nodes). In general, I would avoid attempting to use this property as it can lead to some very hard to debug errors, and prefer the object oriented calling copy constructors.
Edited to add:
There seems to be some confusion on how/why someone would do this: here's a comment I made on the how:
Normally, I see the above on alternate
implementations of vector. The memory
is allocated via
malloc(sizeof(Class)*size) and the
objects are constructed in place via
explicitly called constructors and
destructors. Sometimes (like during
reallocation) they have to be moved,
so the option is to do std::vector's
repeated calling of copy constructors
on new memory and destructors on the
old, or use memcopy and just "free"
the old block. Most times the latter
just "works", but doesn't for all
objects.
As to why, a memcopy (or realloc) approach can be significantly faster.
Yes, it invokes undefined behavior, but it also just tends to work for a majority of objects. Some people consider the speed worth it. If you were really set on using this approach, I would suggest implementing a bitwise_movable type trait to allow types this works for to be whitelisted, and fall back on the traditional copy for objects not in the whitelist, much like the example here.
If the object had no pointers within it, and no virtual functions, no children with any of the same, you might get away with it. It is not recommended!!!
This should be done using a copy or deepcopy function or overridden operators.
In the method you would call a new contructor and copy it's contained data items one by one.
for a shallow copy you would copy pointers / references so you would have two object pointing to the same contained elements.... a potential memory leak nightmare.
for a deep copy you would traverse the contained objects and references making new copies of them also.
To move an object you would copy it and delete the original.
Short answer: std::memcpy() is for moving memory, not for moving objects. Using it nonetheless will invoke undefined behavior.
Somewhat longer answer: A C++ object that isn't a POD might contain resources that need to be freed and which are kept in handles that cannot be easily copied. (A popular resource is memory, where the handle is a pointer.) It also might contain stuff inserted by the implementation (virtual base class instance pointers) that shouldn't be copied as if it were memory.
The only right way to move an object in C++98 and C++03 is to copy-construct it to its new location and invoke the destructor in the old. (In C++1x there will be move semantic so things might get more interesting in certain cases.)
Off the top of my head : If you just do a memcpy you end up doing a shallow copy. If you need a deep-copy then this won't work.
What's wrong with the copy constructor and the assignment operators anyway?
In general (and in all languages, not just C++), in order to safely move an object, you also need to rewrite ALL pointers/references to that object to point at the new location. That's a problem in C++, because there's no easy way to tell if any object in the system has a 'hidden' pointer to the object you're moving. As you've noted, some classes may contain hidden pointers to themselves. Other classes may have hidden pointers in a factory object that tracks all instances. Its also possible for seemingly unrelated classes to cache pointers to objects for various reasons of their own.
The only way to do it safely is if you have some sort of reflective access to all objects in the system so that you can find all the pointers to the object and rewrite them. This is a potentially very expensive operation in any case, so systems that need it (such as copying garbage collectors) tend to be very carefully organized to do the copying of many objects at once and/or bound the places that need to be searched for pointers with write barriers and such.