Moving data from shared_ptr to vector constructor [duplicate] - c++

This question already has answers here:
Is it possible that a pointer gets owned by a vector without any data copy?
(3 answers)
Using std::vector as view on to raw memory
(11 answers)
Closed 1 year ago.
I have a library which contains a function that returns the following:
std::shared_ptr<const uint8_t[]>
and
uint32_t size
I need it to pass it to another API that takes:
std::vector<uint8_t> data
The data contained in the shared_ptr is the exact same data that needs to go into the vector, so a move operation would be ideal.
So my question is this: Is there any way to obtain this without just copying the data? I realize the issue hinges on the fact that shared_ptr will delete the data once it goes out of scope, so I'd like to know if there's a way to circumvent this.
(And if copy is necessary, what is the most efficient method to do so? I'm thinking std::copy or good'ol' memcpy.)

No, it isn't possible for a vector to take ownership of a separately allocated array.
If you need a vector, and the source isn't a vector, then you have to copy (you could move individual elements, but that's same as copying in case of std::uint8_t).
If you wish to avoid a copy, then you must change one of the premises: Either start with a vector (if library permits), or don't create a vector.
I'm thinking std::copy or good'ol' memcpy.
The only reason to use std::memcpy over std::copy is to reinterpret the data (std::copy could be used for that as well, but the syntax becomes clunky with the casts that are necessary) which you aren't doing here.
std::copy is fine as well as the vector constructor that accepts a pair of iterators.
I realize the issue hinges on the fact that shared_ptr will delete the data once it goes out of scope, so I'd like to know if there's a way to circumvent this.
Your intuition is correct that releasing the pointer from ownership of the shared pointer would have been necessary in order to achieve what you want. However, it isn't sufficient since you cannot make vector take that ownership.
But regarding whether there's a way to prevent a shared pointer from deleting the owned pointer: Yes, it is possible by writing a custom deleter class. But the library that creates the shared pointer would have to let you be in control of the deleter which I suspect isn't the case.
This would also be quite dangerous since you would have to make sure that whatever takes ownership of the pointer would have to keep it alive at least as long as the longest living shared pointer to the "released" data... which is quite difficult unless you're in control of all of the shared owners.

Related

Can a std::array<T, N> release its data?

Consider as an example the unique_ptr and its release method that returns a pointer to the managed object and releases the ownership.
Is there any way to release the ownership of the underlying array of a std::array?
Ok, one could use a std::unique_ptr instead of a std::array and that's all. Anyway, the latter has a few nice features like the size member method that are useful sometimes.
Is there any way to release the ownership of the underlying array of a std::array?
No. A std::array is just a wrapper for a raw array. It can be reassigned but that is actually a copy operation of all the elements in the array. The destination array does not point to the source array.
You should also note that a std::array and a std::unique_ptr<type[]> are different in that the std::array size must be know at compile time where the std::unique_ptr<type[]> size can be set at run time. All std::unique_ptr<type[]> really does is wrap a type * name = new type[some_size].
Nope, an std::array is just a simple wrapper around a native array, so it is on the stack and cannot release its contents unless it goes out of scope when the contents are automatically popped from the stack
You should consider using a std::vector instead. Since you are already dealing with an array on the heap. You can then std::move the vector into another one to "transfer" ownership of the contents. For example
another_vec = std::move(old_vec); // now another_vec has the contents
Note If you use a unique_ptr the array you are getting is on the heap and not on the stack! So you might be better off using a std::vector and its data() function instead. But I am not completely sure of your use case.
Another note Another thing that is not that obvious when thinking about using an std::array is that the type is a heavyweight object, this means that the regular rvalue optimizations might not work as optimally since it is not as trivial to move as a vector
«releasing» a std::array basically means calling the destructor and using the memory for something else.
You can explicitly destroy an explicitly constructed std::array by using the std::*::destroy functionality found in the standard library or calling the destructor explicitly.
This is something you usually want to avoid, unless you are implementing very basic data structures where you have no other choice. One use case is if you want to control when and how you construct and destruct a global array without an indirection through a pointer.
C++17 may provide the new functions
destroy_at, destroy and destroy_n to explicitly destruct objects.
See also the C++ FAQ on destructors.

Should i always use smart pointer in C++ 11 [duplicate]

This question already has answers here:
Which kind of pointer do I use when?
(4 answers)
C++ 11: smart pointers usage [duplicate]
(1 answer)
Closed 9 years ago.
From c++ 11 i can write code without create and deleting raw pointers.
But is it the right way to go- Should i always use smart pointers (either shared, unique or weak) or are there situations in which i should delete objects by myself?
It is hard to imagine situations where you would want to manually delete an object, so in that sense, the answer to your question is "yes, always use smart pointers".
However, raw pointers do have another use case. Smart pointers are all about conferring ownership semantics. A unique_ptr has exclusive ownership of the object it points to, and will destroy the object when the pointer goes out of scope. A shared_ptr implements shared ownership, and the object will be destroyed when the last shared pointer goes out of scope.
Raw pointers are still useful for cases where you want to point to an object without indicating any kind of ownership. You're just pointing to an object you know exists, and that someone else (who owns it) will delete it when the time comes.
Raw pointers are for pointing to objects. Smart pointers are for owning objects.
There are really very few cases where you'd want to use a smart
pointer. In most applications, either most deletes will be
delete this, or if the application is transactional, the
transaction manager will take care of the delete. In cases
where this doesn't apply, you generally don't want to use
dynamic allocation to begin with. About the only times you'll
use smart pointers:
For some reason or another, you cannot make the object fully
operational in the constructor, but have to follow up with
additional actions before it is active. In this case, it makes
sense to keep it in an std::unique_ptr until the object is
fully active, then call release.
You really want value semantics, but you also need
polymorphism. In this case, use some sort of shared pointer.
(But beware of cycles.) If the object is mutable, beware too,
since you'll end up with reference semantics.
You really want value semantics (with deep copy), but the
profiler shows that the cost of copying is too high, you might
also consider some sort of shared pointer. This has its
dangers, but for large blocks of immutable data, can be a good
solution.
But for starters, you should always ask yourself: why am
I allocating this object dynamically. The most frequent valid
reason is that it is an entity object, with a lifetime defined
by program logic (i.e. its lifetime ends as a result of some
external event). In such cases, smart pointers will cause more
problems than they solve.

What exactly do we want when we copy a pointer from one object to another of the same class? [duplicate]

This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 9 years ago.
So I'm reading about copy control and the Rule of Three, and it seems that the main example they're giving as to why they're necessary is when using pointers as class members. It says that if you copy the pointer from one object to another, then multiple objects of that class are pointing to the same memory. Why is this bad? Don't we want the object we're pointing things to do point to the same thing? What exactly is supposed to be happening when pointers are copied between classes? I'm not sure exactly what we're supposed to do when using a copy constructor to deal with pointers..
You want to write a copy constructor if you have any dynamic content, in order to avoid shallow (member-wise) copy.
Why would it be a problem if different pointers are pointing to the same object? Because that way, if you change the copy, you change the original.
If you, for example, have two pointers to the same object, and then delete the object by using the first pointer - the object will be gone; the second pointer will not be null, but a dangling pointer, with its previous, but now - invalid value.
Consider: std::vector contains a pointer to an array of elements. If you make a vector, then make a copy of that vector, then change the copy, you don't want the changes to the copy to also change the original. And if you insert elements into the copy, to the point where the array has to be deallocated and resized, the original vector now points to deallocated memory.
The point of the Rule of Three is to prevent copies from having any residual link to their originals. Copies are meant to be independent. There are exceptions to this (google "copy on write"), but they too require special handling and tracking -- again, in the copy constructor, assignment operator, and destructor.
The copy constructor is a tool that allows you to create another object of the same class by copying an existing one not by construction of new object.
If you would have copied pointers that way so they're pointing on the same place in the memory you would create another pointers to in fact the same object instead of creating a new one. It's like creating a shortcut to file in windows :-)
Copy constructor should copy every component of object into another place of memory and provide new pointers to this place, and that way create effective copy of an object.
If you have two object sharing a pointer then if you make a change to one object it will also change the other object. Normally (but not always) this is considered a bad thing.
Additionally if two objects share a pointer then you have the issue of who is responsible for deleting the pointer.
There is actually a standard class called std::shared_ptr which implements shared pointers and automatically manages the memory for you. If you want a class that shares pointers then you should use this class. This way you will not need to worry about the rule of three.
It's bad, because when you delete the object pointer by the pointed in one object, the pointer in the other object will point at invalid memory. That's why straight up assigning the pointer is risky. That's the most dangerous part. But that's not all. If you have two pointers that point to the same place in the memory, changing the memory via one pointer will also change the contents of the second pointer. Sometimes it can make changes in an object you won't expect to change and leave you with searching a bug for days.
And to answer to your second qestion:
What exactly is supposed to be happening when pointers are copied between classes?
Well... it depends on what you want. If you just want to point to something in the memory, and never change it, or delete it, then simply assigning one pointer to another is a valid idea. However, if you'll want to change the object under the pointer, it's much safer to do a copy of it first (via the new operator and the assigment operator), and then point to the new object with the second pointer.

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.

Raw Pointer in C++

I have a piece of C++ classes and I have the raw pointer to the objects. The pointer to the object would get passed down to the function. The problem is the underlying function might need to store the pointer at times in an STL container in which pointer to the object would be used later on. If I am not using shared_ptr, I am thinking of adding a bool flag to the class which indicates whether the caller of the function is responsible for deleting the object memory. Would that be fine?
Thanks.
Messy. And rife with many potential bugs that will keep you at work well past midnight on a Saturday.
Be clear and consistent about resource ownership. Either the vector owns the pointers, or some specific function owns the pointers, or smart pointers own pointers. Any mixing of these semantics will have the ultimate result of you tearing your hair out late at night.
The best solution is usually to use a reference-counted smart pointer. (As you probably already know all to well, you can't use std::auto_ptr) Barring that, create a class whose sole purpose in life is to allocate, deallocate and grant access to the vector's contained pointers. Any function that needs the contained object would go through your manager class to get to them.
STL containers will almost certainly take a copy of the object which you insert into it. When the object is removed from the container, the object will be destroyed.
If the default copy constructor is not sufficient (i.e. you need to do a deep copy of the object), you need to ensure you implement your own version which does the copy properly.