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

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.

Related

Moving data from shared_ptr to vector constructor [duplicate]

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.

Is std::unique_ptr the wrong tool to allocate memory for an array?

I have an array of (for example) uint8_ts.
Is std::unique_ptr the wrong tool to use to manage this object in memory?
For example,
std::unique_ptr<uint8_t> data(new uint8_t[100]);
Will this produce undefined behaviour?
I want a smart-pointer object to manage some allocated memory for me. std::vector isn't ideal, because it is a dynamic object. std::array is no good either, because the size of allocation is not known at compile time. I cannot use the [currently, 2016-03-06] experimental std::dynarray, as this is not yet available on Visual Studio 2013.
Unfortunately I have to conform to VS2013, because, rules.
The way you're using the unique_ptr will indeed result in undefined behavior because it'll delete the managed pointer, but you want it to be delete[]d instead. unique_ptr has a partial specialization for array types to handle such situations. What you need is
std::unique_ptr<uint8_t[]> data(new uint8_t[100]);
You can also use make_unique for this
auto data = std::make_unique<uint8_t[]>(100);
There is a subtle difference between the two, however. Using make_unique will zero initialize the array, while the first method won't.
Certainly unique_ptr as you've used it is incorrect because it will call delete rather than delete[] to deallocate the memory.
The normal solution to this situation is std::vector: It allocates and manages your memory as well as providing a fairly robust interface. You say that you don't want to use vector because True, but would be risky to expose that functionality to the user. from which I infer you're exposing the implementation detail of your container type to the interface of your class. That then is your real problem.
So use vector to manage the memory but don't expose vector directly in your class interface.

Is it a bad idea to replace POD C-style array with std::valarray?

I'm working with a code base that is poorly written and has a lot of memory leaks.
It uses a lot of structs that contains raw pointers, which are mostly used as dynamic arrays.
Although the structs are often passed between functions, the allocation and deallocation of those pointers are placed at random places and cannot be easily tracked/reasoned/understood.
I changed some of them to classes and those pointers to be RAIIed by the classes themselves. They works well and don't look very ugly except that I banned copy-construct and copy-assignment of those classes simply because I don't want to spend time implementing them.
Now I'm thinking, am I re-inventing the wheel? Why don't I replace C-style array with std:array or std::valarray?
I would prefer std::valarray because it uses heap memory and RAIIed. And std::array is not (yet) available in my development environment.
Edit1: Another plus of std::array is that the majority of those dynamic arrays are POD (mostly int16_t, int32_t, and float) arrays, and the numeric API can possibility make life easier.
Is there anything that I need to be aware of before I start?
One I can think of is that there might not be an easy way to convert std::valarray or std::array back to C-style arrays, and part of our code does uses pointer arithmetic and need data to be presented as plain C-style arrays.
Anything else?
EDIT 2
I came across this question recently. A VERY BAD thing about std::valarray is that it's not safely copy-assignable until C++11.
As is quoted in that answer, in C++03 and earlier, it's UB if source and destination are of different sizes.
The standard replacement of C-style array would be std::vector. std::valarray is some "weird" math-vector for doing number-calculation-like stuff. It is not really designed to store an array of arbitrary objects.
That being said, using std::vector is most likely a very good idea. It would fix your leaks, use the heap, is resizable, has great exception-safety and so on.
It also guarantees that the data is stored in one contiguous block of memory. You can get a pointer to said block with the data() member function or, if you are pre-C++11, with &v[0] for a non-empty vector v. You can then do your pointer business with it as usual.
std::unique_ptr<int[]> is close to a drop-in replacement for an owning int*. It has the nice property that it will not implicitly copy itself, but it will implicitly move.
An operation that copies will generate compile time errors, instead of run time inefficiency.
It also has next to no run time overhead over that owning int* other than a null-check at destruction. It uses no more space than an int*.
std::vector<int> stores 3 pointers and implicitly copies (which can be expensive, and does not match your existing code behavior).
I would start with std::unique_ptr<int[]> as a first pass and get it working. I might transition some code over to std::vector<int> after I decide that intelligent buffer management is worth it.
Actually, as a first pass, I'd look for memcpy and memset and similar functions and make sure they aren't operating on the structures in question before I start adding RAII members.
A std::unique_ptr<int[]> means that the default created destructor for a struct will do the RAII cleanup for you without having to write any new code.
I would prefer std::vector as the replacement of c-style arrays. You can have a direct access to the underlying data (something like bare pointers) via .data():
Returns pointer to the underlying array serving as element storage.

Dynamic Pointers and Objects

I have to write an application to complete an assignment, at school. To do so, we have to create a dynamic array. My question is:
If I create a structure containing a dynamic pointer, and copy it, does the memory get copied too?
For instance:
struct SomePointerStruct
{
int* p_array;
}
What happens if I copy that structure? Also,
Do I need to clean up the original pointer?
By default, objects in c++ are copied byte-by-byte. that means that the pointer will be copied, and you will get two pointers pointing to the same array.
To fix this, you need to implement a copy constructor and should also override the operator=. Also, you may want to delete this array when you finish, so implement also a destructor. That is "the rule of three".
If I create a structure containing a dynamic pointer, and copy it,
does the memory get copied too?
No.
Much of the design of the C++ language is dictated by the edict, "You don't pay for what you don't need." One way this plays out is if you want to deep-copy something, you have to do it yourself.
Do I need to clean up the original pointer?
In general, yes.
For every new, there must be exactly one matching delete. If you instantiate a SomePointerStruct, and the construction of that calls new, that's one delete you need somewhere -- probably in SomePointerStruct's destructor. If you create a copy of SomePointerStruct and the copy deep-copies the original pointer (calling new), then that's a second delete you need -- again, probably in the destructor.
To avoid repeating the whole chapter named Memory from your C++ book, I'll answer with that:
Raw pointers shouldn't own memory.
By consequence:
struct SomePointerStruct { int x; }
is trivially copyable, and:
struct SomePointerStruct { std::unique_ptr<int> x; }
is noncopyable (but it's moveable). That extends to all of your other types (if they are properly constructed), sans the "trivially", perhaps. The fact that the pointer value would be copied in your original example would of course lead to a lot of problems, but since they can be easily avoided by using what I wrote above, it's kind of off the scope WRT such a simple assignment.
A whole another thing would be a non-owning pointer case, in which a copied struct would, of course, point to the same region of memory. You lose all the guarantees of the pointer pointing to a valid location, though, so a reference would be preferred.
As for creating of a dynamic array, you'd be best off with simply using std::vector.

Pointer to vector vs vector of pointers vs pointer to vector of pointers

Just wondering what you think is the best practice regarding vectors in C++.
If I have a class containing a vector member variable.
When should this vector be declared a:
"Whole-object" vector member varaiable containing values, i.e. vector<MyClass> my_vector;
Pointer to a vector, i.e vector<MyClass>* my_vector;
Vector of pointers, i.e. vector<MyClass*> my_vector;
Pointer to vector of pointers, i.e. vector<MyClass*>* my_vector;
I have a specific example in one of my classes where I have currently declared a vector as case 4, i.e. vector<AnotherClass*>* my_vector;
where AnotherClass is another of the classes I have created.
Then, in the initialization list of my constructor, I create the vector using new:
MyClass::MyClass()
: my_vector(new vector<AnotherClass*>())
{}
In my destructor I do the following:
MyClass::~MyClass()
{
for (int i=my_vector->size(); i>0; i--)
{
delete my_vector->at(i-1);
}
delete my_vector;
}
The elements of the vectors are added in one of the methods of my class.
I cannot know how many objects will be added to my vector in advance. That is decided when the code executes, based on parsing an xml-file.
Is this good practice? Or should the vector instead be declared as one of the other cases 1, 2 or 3 ?
When to use which case?
I know the elements of a vector should be pointers if they are subclasses of another class (polymorphism). But should pointers be used in any other cases ?
Thank you very much!!
Usually solution 1 is what you want since it’s the simplest in C++: you don’t have to take care of managing the memory, C++ does all that for you (for example you wouldn’t need to provide any destructor then).
There are specific cases where this doesn’t work (most notably when working with polymorphous objects) but in general this is the only good way.
Even when working with polymorphous objects or when you need heap allocated objects (for whatever reason) raw pointers are almost never a good idea. Instead, use a smart pointer or container of smart pointers. Modern C++ compilers provide shared_ptr from the upcoming C++ standard. If you’re using a compiler that doesn’t yet have that, you can use the implementation from Boost.
Definitely the first!
You use vector for its automatic memory management. Using a raw pointer to a vector means you don't get automatic memory management anymore, which does not make sense.
As for the value type: all containers basically assume value-like semantics. Again, you'd have to do memory management when using pointers, and it's vector's purpose to do that for you. This is also described in item 79 from the book C++ Coding Standards. If you need to use shared ownership or "weak" links, use the appropriate smart pointer instead.
Deleting all elements in a vector manually is an anti-pattern and violates the RAII idiom in C++. So if you have to store pointers to objects in a vector, better use a 'smart pointer' (for example boost::shared_ptr) to facilitate resource destructions. boost::shared_ptr for example calls delete automatically when the last reference to an object is destroyed.
There is also no need to allocate MyClass::my_vector using new. A simple solution would be:
class MyClass {
std::vector<whatever> m_vector;
};
Assuming whatever is a smart pointer type, there is no extra work to be done. That's it, all resources are automatically destroyed when the lifetime of a MyClass instance ends.
In many cases you can even use a plain std::vector<MyClass> - that's when the objects in the vector are safe to copy.
In your example, the vector is created when the object is created, and it is destroyed when the object is destroyed. This is exactly the behavior you get when making the vector a normal member of the class.
Also, in your current approach, you will run into problems when making copies of your object. By default, a pointer would result in a flat copy, meaning all copies of the object would share the same vector. This is the reason why, if you manually manage resources, you usually need The Big Three.
A vector of pointers is useful in cases of polymorphic objects, but there are alternatives you should consider:
If the vector owns the objects (that means their lifetime is bounded by that of the vector), you could use a boost::ptr_vector.
If the objects are not owned by the vector, you could either use a vector of boost::shared_ptr, or a vector of boost::ref.
A pointer to a vector is very rarely useful - a vector is cheap to construct and destruct.
For elements in the vector, there's no correct answer. How often does the vector change? How much does it cost to copy-construct the elements in the vector? Do other containers have references or pointers to the vector elements?
As a rule of thumb, I'd go with no pointers until you see or measure that the copying of your classes is expensive. And of course the case you mentioned, where you store various subclasses of a base class in the vector, will require pointers.
A reference counting smart pointer like boost::shared_ptr will likely be the best choice if your design would otherwise require you to use pointers as vector elements.
Complex answer : it depends.
if your vector is shared or has a lifecycle different from the class which embeds it, it might be better to keep it as a pointer.
If the objects you're referencing have no (or have expensive) copy constructors , then it's better to keep a vector of pointer. In the contrary, if your objects use shallow copy, using vector of objects prevent you from leaking...