How to make an array that holds unique_ptrs? - c++

I am under the assumption that the code bellow is a unique_ptr to an array (aka not what I want)
std::unique_ptr<int[]> arr;
arr = std::make_unique<int[]> (5);
arr[0] = *new int(1);
delete &arr[0]; // malloc error, want to avoid "delete"
However, I want an array that holds unique_ptrs like so...
std::unique_ptr<int> arr2 []; //Error, requires explicit size
arr2 = std::make_unique<int> [5]; //Desirable, does not compile
arr2[0] = std::make_unique<int>(1); //Desirable, does not compile
How do I go about making an array of unique_ptrs? If that is not possible, then how do I deal with a malloc error?

Do you want an array that holds unique_ptrs (as in the title), or a unique_ptr holding an array (as in your examples)?
If an array of unique_ptrs is what you want, then
std::vector<std::unique_ptr<int>>
or
std::array<std::unique_ptr<int>, 3>;
(for example) will do the job.
If a unique_ptr holding an array is what you're after, then unique_ptr<int[]> will work (there is a partial specialisation of unique_ptr to support it), although you can't use std::make_unique and will need to call operator new[] yourself:
std::unique_ptr<int[]> p{new int[42]};
However, if you think you need this, what you most likely really want is std::vector, and I'd strongly recommend using that instead.

Short answer: use vectors. They are much easier to work with and you don't have to explicidly allocate memory. You should also use typedefs for syntax simplicity.
typedef unique_ptr<int> intPtr;
vector<intPtr> vec;
vec.push_back(make_unique<int>(69));
auto myIntPtr = make_unique<int>(16);
vec.push_back(move(myIntPtr)); // unique ptrs cannot be copied, must be moved
unique_ptr<int[5]> p1; // valid syntax

std::unique_ptr<int[]> arr;
arr = std::make_unique<int[]> (5);
At this point you have a unique_ptr to an array of int. This sounds like it is exactly what you want.
arr[0] = *new int(1);
But this is questionable. It dynamically allocates a single int, assigns 1 to the allocated int, then it assigns the value, 1, at the allocated int into the array at element 0. the allocated int is left hanging with nothing pointing at it, and is now exceptionally difficult to `delete. This is a memory leak.
delete &arr[0]; // malloc error, want to avoid "delete"
And as you've seen, this is fatal. Rather than attempting to delete the leaked int, delete has been invoked with a pointer to the array stored in the unique_ptr. Eventually the unique_ptrwill try todelete` the array and fail because it's already gone.
Based on comments, OP intends
std::unique_ptr<int*[]> arr;
arr = std::make_unique<int*[]> (5);
arr[0] = new int(1);
delete arr[0];
But I'd like to talk them out of this idea. Let's look at their end goal: a templated class
template <class TYPE>
class MyVector
{
std::unique_ptr<TYPE[]> arr; // array of whatever type
public:
MyVector(size_t size): arr(std::make_unique<TYPE[]> (size))
{
}
TYPE& operator[](size_t index)
{
return arr[index];
}
// note the complete lack of growing, shrinking and other vector goodness
// as they are not needed for this example.
};
We can use this class with just about anything.
int main()
{
// vector of int
MyVector<int> vec(5);
vec[0] = 1;
// vector of pointer to int (yuck)
MyVector<int*> vec2(5);
vec2[0] = new int(1);
delete vec2[0];
// vector of smart pointer to int (also yuck, but less yuck)
MyVector<std::unique_ptr<int>> vec3(5);
vec3[0] = std::make_unique<int>(1);
// vector of std::string
MyVector<std::string> vec4(5);
vec4[0] = "I am the very model of a modern major general...";
}
If the user of the vector want it to contain pointers, they can say so. There is no reason to force the user to use a pointer.

Related

An error proof way to apply new operator for pointer to array

In C, I do
int (*ptr)[100];
ptr=malloc(sizeof *ptr); // this is the easy/error proof way of doing it
Is there an error proof C++ way of doing the same with new operator
int (*ptr)[100];
ptr=new __what_comes_here?
int (*ptr)[100];
means ptr is a pointer, which should hold an address of an array of 100 integers. In other words, technically if you have, something like:
int arr[100]; // automatic (compile time allocated) object of 100 integers
Then you may want to use:
ptr = &arr;
But that is not the case here. So you can do with a simple pointer. If you want to go dynamic then you either go for malloc equivalent:
int *p = new int[100]; // do `delete[] p` later to reclaim memory
Note that, p is a simple pointer, which holds the address of the first integer of the dynamically allocated array.
But better practice is to use standard container to avoid any memory management:
std::vector<int> v(100);
If the size 100 is fixed then you may use:
int a[100]; // C-style
Or
std::array<int, 100> arr; // C++11 onwards
If you require new and don't have luxury of using above facilities but still want automatic reclamation of memory then use unique_ptr as following:
std::unique_ptr<int[]> p(new int[100]);
The way I'm showing here is obviously not a great solution, I just wanted to sort of answer the question in a unique way.
template<typename>
struct deref;
template<typename T>
struct deref<T*>
{
typedef T type;
};
int main() {
int (*ptr)[100];
ptr = new deref<decltype(ptr)>::type[1];
return 0;
}
I know that the [1] is obviously highly suspicious but without it, the result of the new seems to just decay to a int*. So I think that adding it causes only the "outer" array to decay and leave the inner intact.
Also this means that you need to call delete[] to clean it up and not cause undefined behaviour.
If you want to convince yourself that this actually allocates the necessary space and it can access it correctly you can see the output of godbolt in an example.
typedef int IntArray[100];
int main()
{
IntArray* p = new IntArray[1];
delete[] p;
return 0;
}
Note that you must deallocate thus allocated array with delete[].
Not quite what you asked for, but you can what you want using template type deduction.
template <typename T, std::size_t N>
void populate_ptr(T (*&ptr)[N])
{
// Its a shame the return value of new T[N] is T*, not T(*)[N]
ptr = reinterpret_cast<T(*)[N]>(new T[N]);
}
int (*ptr)[100];
populate_ptr(ptr);
// Don't forget to delete[](ptr) later!
You can't deduce templates on return values, so you can't use assignment, but passing-by-reference should be equivalent for all use-cases.
Not that this is a great way of handling this, but being able to do template type deduction against C-style arrays comes in handy from time to time..

Array as return value of a function

Is there a way to return an array as a result of a function in c++?
int* returnArray()
{
int* arr = new int[3];
return arr;
}
This way arr is a local variable and the alocated memory block is lost after the function returns.
Is there any way around this besides defining an array outside the function block?
Allocated memory block is not lost, since the memory is allocated on the heap. The pointer to this memory is copied, and correctly returned to the caller. In other words, there is nothing wrong with your code - except possibly for the fact that the caller must know the array size in order to do anything useful with the returned array.
The anti-pattern you are probably referring to looks like this:
// WRONG: returns pointer to local data
int* returnArray() {
int arr[3] = {1, 2, 3};
return arr;
}
This is an error because arr is allocated on the stack, and the function returns a pointer to that data. To fix it, one would need to declare the function as returning an array, but C++ doesn't allow this, so it must be done indirectly. Fixed function would then look like this:
struct Array {
int array[3];
};
// correct: generated copy constructor correctly copies arr
Array returnArray() {
Array arr = {{1, 2, 3}};
return arr;
}
In production code, and if you can use C++11, your function would simply return std::array<int, 3>. C-style arrays are almost always used in low-level code to implement containers and there is almost never a need to directly return them from functions.
You're returning a pointer to an array it's OK, but the problem is "who is responsible to delete it", you can use smart pointers:
std::unique_ptr<int[]> returnArray()
{
std::unique_ptr<int[]> arr (new int[3]);
return arr;
}
And everyone is happy. Also, you can use std::vector.
std::vector<int> returnArray()
{
std::vector<int> arr(3);
return arr;
}
Your function is okay as is. Memory obtained with a new expression is never deallocated until you use a delete expression.
This is the version that would lose the memory when the function returns:
// WRONG:
int* returnArray()
{
int arr[3];
return arr;
}
The even better way would be to return a std::vector<int>.
What you have works; the issue is that you've made the caller responsible for remembering to delete the dynamic array. This is a good recipe for a memory leak.
Perhaps you were thinking of trying to return a local array:
int * returnArray() {
int arr[3];
return arr; // BOOM! dangling pointer
}
This is wrong, since this array is destroyed when the function returns; using the pointer after that will give undefined behaviour.
To solve both issues, return a managed dynamic array:
std::vector<int> returnVector() {
std::vector<int> v(3);
return v;
}
Actually, you're code is fine but dangerous, I mean, allocated memory for arrremains until you call delete[] on it, meaning that you can safely access array's elements but delegating memory clean up to source code using this method is a bad practice and will, most probably, lead to a memory leak or corruption.
I would recommend passing the array as a parameter so calling code is in charge of memory management:
void returnArray(int* arr)
{
... Your code here managing array's contents ...
}
Or, if this is one class' method, manage this memory from inside this class.
Edit: Or better, use smart pointers as suggested by #M M.

Is it possible to swap arrays of structs (in linear time)?

I have a small program computing the forces of planets on each other. My program has two arrays of structs, one that holds the positions and velocities before iterations, and the other holds what their positions and velocities will be after the iterations.
At the end of each iteration, I'd like to move the values from the second array into the first and the second array can become garbage (but needs to point to some valid memory location I can write to later). I thought I could simply switch the arrays since an array is a pointer, but the compiler won't let me.
Consider this example:
typedef struct { int a; } Foo;
int main()
{
Foo bar[8], baz[8];
Foo *temp = baz;
baz = bar; //ISO C++ forbids the assignment of arrays
bar = temp; //incompatible types in assignment of Foo* to Foo[8]
}
This is what I'd like to do. It would certainly be faster than a for loop from 1 to N.
You should consider using std::vector which can be swapped in constant time:
std::vector<Foo> bar(8), baz(8);
std::swap(bar, baz);
Or if you don't want to do that and instead want to manually manage your memory, you can use new[] to get a pointer to an array on the free store and swap the pointers when you want to swap the arrays.
If you must have your arrays on the stack, the only way to do this without actually swapping each element would be to create the arrays on the stack and instead of using the arrays, use pointers to the arrays:
Foo bar[8], baz[8], *pbar = bar, *pbaz = baz;
// ...
// this code only using pbar and pbaz
// ...
// swap the pointers
std::swap(pbar, pbaz);
// ...
// use pbar and pbaz some more
// ...
Here's where you went wrong:
since an array is a pointer
This is not true. Arrays decay to a pointer, but they are not the same thing.
However you can easily do what you want here by actually getting pointers from those arrays.
Foo bar[8], baz[8];
// load bar up with valid data
Foo *data = bar;
Foo *garbage = baz;
// compute next step
std::swap(data,garbage);
Also consider using std::array rather than raw arrays (it has properties more consistent with other types in C++ and is less 'special' than raw arrays). Then when you use pointers to these arrays the size of the array won't be discarded the way it is for pointers to raw arrays.
std::array<Foo,8> bar, baz;
std::array<Foo,8> *data = &bar;
std::array<Foo,8> *garbage = &baz;
// compute next step
std::swap(data,garbage);
If you need dynamically sized arrays use std::vector, and then you can just swap the vectors directly rather than swapping pointers to the vectors, because swapping vectors will be implemented to swap the pointers inside the vectors.
std::vector<Foo> data, garbage;
// compute next step
std::swap(data,garbage);
The problem is that you're using a stack-allocated array.
When you say Foo bar[8];, you're creating space for eight Foo structs in the current stack frame. So the reason you can't assign it to something else is that it'd have to move outside the frame somehow, escaping the memory management and scoping it's supposed to have.
You want a dynamically-allocated array - Foo* bar = new Foo[8];. When you're done with it, delete[] bar;. The difference here is that now the pointer is on the stack, but the actual contents are on the heap - so you can change the location the pointer references without having to worry about moving the actual pointer itself.
Another option is to use a class with a copy-constructor and operator=, like std::vector, std::list, or std::deque.
Incidentally, the procedure of copying the array contents is linear time. A pointer assignment is constant time (O(1)) because it doesn't matter how large your array gets - it's always one operation to move the pointer.
You could use memcpy:
int main()
{
Foo bar[8], baz[8], temp[8];
memcpy(temp, baz, sizeof(Foo) * 8);
memcpy(baz, bar, sizeof(Foo) * 8);
memcpy(bar, temp, sizeof(Foo) * 8);
}
You can declare your arrays as temps, and also declare pointers - which you will use for the rest of the function.
Those ponters can be easily swapped.
int main()
{
Foo temp1[8], temp2[8];
Foo *bar = temp1, *baz = temp2;
Foo *temp = baz;
baz = bar; //no problems now
bar = temp;
}
Foo bar[8], baz[8];
Then
Foo* arr1 = bar, arr2 = bax;
Forget about baz & bar, work only with arr1 and arr2.
Swap:
int* temp = arr1;
arr1 = arr2;
arr2 = temp;

Is there a way to traverse shared_ or any "smart" ptr over an array?

From what I know smart pointer should be equilvalent to "raw" pointer with the difference that it is safe. Ok, but if I have regular pointer:
int* p = new int[10];
fill(p, p + 10, 0);//this will work for regular pointer but not for smart one.
Same with hand written loop:
for(int i = 0; i < 10; ++i)
{
*p[i] = 0;
}
This is not possible (I think) for smart poiner. So the question is, how can I initialized array to which pointer I have stored in one of smart pointers (let's assume shared_ptr)?
First off, it might be easier just to use std::vector<int>. If your array has an unchanging size, though, then perhaps std::vector<int> is indeed better replaced with a smart pointer.
With that out of the way, your first choice should be a std::unique_ptr, specifically the array specialization: std::unique_ptr<int[]>. (If you don't, the smart pointer will use delete instead of delete[] on your pointer, leading to undefined behavior.) Your code would become:
std::unique_ptr<int[]> p(new int[10]);
std::fill(p.get(), p.get() + 10, 0);
As you can see, smart pointers have a get() method that returns the underlying pointer.
From here, if you need to use a std::shared_ptr, things become a big dangerous (do to unfortunate oversight, as far as I know). That oversight is that std::shared_ptr has no array specialization:
{
std::shared_ptr<int> x(new int[10]);
} // oops! calls delete x.get(); instead of delete [] x.get(); ... UB!
However, std::shared_ptr can easily correct this like so:
{
std::shared_ptr<int> x(new int[10], std::default_delete<int[]>());
} // correctly uses delete [] x.get()
From this point, the code is the same:
std::shared_ptr<int> p(new int[10], std::default_delete<int[]>());
std::fill(p.get(), p.get() + 10, 0);
Note that std::shared_ptr provides a constructor to construct from a std::unique_ptr, which properly uses the deleter. So this is safe:
std::unique_ptr<int[]> p(new int[10]);
std::shared_ptr<int> p2(std::move(p)); // okay, uses std::default_delete<int[]>()
Suppose you declare your array using a smart-pointer like this:
boost::shared_array<int> p = new int[10];
The call to your fill-function would the look like this:
fill(p.get(), p.get() + 10, 0);
p.get() returns the raw pointer that is managed by the smart-pointer. Your loop would require no adjustment, but it was wrong in the first place:
for(int i = 0; i < 10; ++i) {
p[i] = 0; // no dereferencing required here
}

std::vector Destruction and Unexpected Memory Leak

Consider the following example:
#include <vector>
class Foo {
std::vector<int*> v;
public:
Foo() {
this->v.push_back(new int(23));
this->v.push_back(new int(24));
this->v.push_back(new int(25));
}
~Foo() {
}
};
int main() {
Foo f;
return 0;
}
When f goes out of scope in main(), f's destructor is called, which should indirectly free f.v. According to this, the destructor of each element of the vector v should now be called.
However, when I run this program in valgrind, I find that the int*'s were not deallocated.
$ valgrind --leak-check=full ./a.out
What am I missing here?
std::vector<T> does indeed call the destructor of T when it is destroyed. Here T is int *. The destructor of int * does nothing. The storage for the int * itself is freed, but the ints they point to are not.
Consider:
int main() {
int *x = new int(23);
return 0;
}
This exhibits the same problem; when x goes out of scope, its destructor is indeed called, and the storage for the pointer that is x is freed, but since the destructor of a pointer is a no-op, the pointed-to int is not freed.
More to the point, vector doesn't know how the ints were allocated. They might be allocated by new int, but they could also point to elements inside an array allocated with new int[200], or they might point to malloc'd data, or they might point into a mmap'd buffer, or they might point to struct elements, or two vectors might be pointing to the same ints... etc. vector isn't smart enough to divine what you want done with these, and so it leaves them alone (additionally, giving vector logic to delete pointed-to elements would break vectors of non-pointer elements such as std::vector<int>, as you can't delete an int!)
You need to either use a std::vector<int>, or use a smart pointer in conjunction with it, eg std::vector<boost::shared_ptr<int> >. Note that using smart pointers may add overhead; with C++0x you should be able to use std::vector<std::unique_ptr<int>> in conjunction with std::move to avoid this overhead. Boost also has pointer vectors that free the pointed-to elements as you expected as well.
The destructor of each element of the vector v should now be called
Yes: the int* objects stored in the vector are destroyed (which is effectively a no-op). The objects pointed to by the pointers in the container are not destroyed.
Consider the following, equally valid program:
{
int x;
std::vector<int*> v;
v.push_back(&x);
} // x cannot be delete'd because it isn't dynamically allocated.
You should use a smart pointer, like std::unique_ptr or shared_ptr so that you don't have to worry about the memory management (do not use std::auto_ptr; it is incompatible with the Standard Library containers because it isn't really copyable). If you don't use a smart pointer then you need to destroy the dynamically objects yourself; doing this correctly is rather difficult.
Each element of your vector is an int *. When an int * is destroyed, the language does not automatically call delete on it. In other words, it's the pointer being destroyed, not the pointee.
Since you are using the new keyword, the integers are being allocated on the heap rather than the stack. In other words, they are being allocated dynamically. In other words, you need to clean up after it.
The "destructor" for a pointer type is to simply delete that pointer. It does not touch the data which is located at the memory address stored by the pointer. Consider the following example:
int a = 5;
int* i = &a;
if (true)
{
int* j = i;
} //j goes out of scope, should *i and a be deleted? no.
So you will need to do this in the destructor:
std::vector<int*>::iterator iter;
for (iter = v.begin(); iter != v.end(); iter++)
{
delete *iter;
}