create a dynamic array while delaying object construction - c++

I'd like to be able to "somehow" create a dynamic array that would still let me build its elements using the new operator.
Here's what I'd like to achieve:
A* a = new A[3]; //or any equivalent syntax
new (&a[0]) A(myparams1); //placement new on first slot
new (&a[1]) A(myparams2, ...); //placement new on 2nd slot
new (&a[2]) A(myparams3, ...); //placement new on 3rd slot
delete[] a; //correct deletion of all elements
I'm aware that this code would work (minus the 3 elements overwritten), but I'd like to avoid creating 3 default a elements in the first call to new[]. I am assuming here that I will always place 3 elements before calling delete[].
I'm thinking such a thing can be achieved by using intelligent calls to A::operator new[] but I'm not sure how.
Does anyone have any idea? it's mostly for curiosity

You just get raw memory instead:
void* mem = ::operator new(capacity * sizeof(A));
This is required to be aligned for any type, including an array of A's. Now you can construct in it:
for (std::size_t i = 0; i < capacity; ++i)
{
void* addr = static_cast<char*>(mem) + i * sizeof(A);
new (addr) A(x, y, z, ...);
}
Destruction requires you explicitly invoke it:
for (std::size_t i = 0; i < capacity; ++i)
{
void* addr = static_cast<char*>(mem) + i * sizeof(A);
static_cast<A*>(addr)->~A();
}
And now you can free the raw memory:
::operator delete(mem);
Note that none of this is exception-safe. It's also what std::vector<A> does, check out the code.

Use operator new.
A a* = (A*) ::operator new(sizeof(A) * 3);
new (&a[0]) A(/* whatever */);
//do stuff
a[0].~A();
::operator delete(a);
Pay careful attention to manually calling the destructors. When using placement new the destructor is not called automagically so it's up to you.

You can create array of pointers.
A ** a = new A*[3]
a[0] = new A;
a[1] = new A;
a[2] = new A;
You need to call delete on each allocated element
delete a[2];
delete a[1];
delete a[0];
And to delete array itself delete[] a;

Related

Is it safe to delete an array pointer in C++ after reassignment?

Suppose I'd like to swap two array pointers in C++ which I have allocated with new [] and different length. Is it safe to delete [] them after swapping? What if they have the same length?
int *a;
int *b;
int *tmp;
a = new int[5];
b = new int[10];
tmp = a;
a = b;
b = tmp;
delete [] a;
delete [] b;
Yeah, you can. The reason being is that the information needed to accurately free up that memory is managed by the free store (the heap in most cases). So it knows how to delete based on address rather than variable. Often times this information is held in *(ptr - x) where x is the size of the tracking data.
Is it safe to delete [] them after swapping?
Yes.
What if they have the same length?
The length is irrelevant.
Yes, you can surely delete the pointer once your swapping is done. As you no longer need to point your array so in that case, it is safe to delete after swapping.
int *a;
int *b;
int *tmp;
a = new int[5];
b = new int[10];
tmp = a;
a = b;
b = tmp;
delete [] a;
delete [] b;
And this is the correct way of doing it. Great Job

C++ delete[] vs. delete in array of arrays

I know that if I use new[] I have to delete[], but this is my doubt:
Declaration:
char **data; // This will be a bi-dimensional array
Construct:
data = new char*[10];
for (int i=0; i<10; ++i)
{
data[i] = new char[128];
}
Destroy:
for (int i=0; i<10; ++i)
{
delete data[i]; // <--- delete or delete[] ???
}
delete[] data;
Another case where I have an array of objects:
Declaration:
myClass **object;
Construct:
object = new myClass*[10];
for (int i=0; i<10; ++i)
{
object[i] = new myClass();
}
Destroy:
for (int i=0; i<10; ++i)
{
delete object[i]; // <--- this object[] is not an array, right?
}
delete[] object; // <--- Is this correct?
You basically answered your own question. Since data[i] is an array, you need to delete[]. object[i] was allocated with new so you would delete it. Since both object and data are arrays, you would need to delete[] them.
The first dimension of your pointer data is an array. The second dimension is an array as well. Therefore you must use delete[] to properly deallocate memory reserved from your new[].
For your object, the first dimension was allocated using new. So you must use delete. Then use delete[] on object because it's an array.
The mnemonic that you mentioned (delete [] for new [] and delete for new) is a a good practice, and should be enforced as mandatory.
However, there is a huge difference between delete and delete[] when it comes to base types (int, char, void*,etc) and classes.
The difference between new and malloc is that one calls the constructor while the other doesn't. Same relation happens with delete and free when it comes to destructor.
In your example you gave two situations : one when an array of simple type is allocated and one with an array of objects allocated.
The behavior is different.
For the simple type, delete and delete[] will produce the same result .
Reason ? well, you basically allocated a block of 10 pointers of char* , so deleting it is no problem (the allocated memory paged will be freed).
In other words, if you have
char* a = new char[100];
then
delete a;
and
delete[] a;
will produce the same results (note that you used a new []);
This behavior is different when it comes to objects that have constructors and destructors.
Let's take the following class :
class SimpleClass
{
public:
SimpleClass(){printf("constructed");
~SimpleClass()(printf("destructed");
}
and the following code :
SimpleClass* arr1 = new SimpleClass[5];
SimpleClass* arr2 = new SimpleClass[5];
char* arr3 = new char[5];
char* arr4 = new char[5];
delete[] arr4;
delete arr3;
delete[] arr2;
delete arr1; //notice the surprise ?
Run the above code (if you can) in Visual Studio and open up a memory viewer. You will see that the memory allocated at ptrs arr4 and arr3 is correctly invalidated, same for arr2.
However when attempting to delete arr1 without the [] call you will get a SigSev error .
Why ?
Because in case of arr2 you have an array of allocated objects, and the delete[] statement means "pass through each destructor from the array"".
In case of arr1 it means : call the destructor of the object allocated at pointer arr1... a bit unfortunate if you take into account that there is more then 1 object allocated at that address, and you end up attempting to release a page which is lesser then the initial allocated size.
Bottom line :
delete[] for new[] and delete for new !
Works every time !

How memory will be deleted?

Let's say I have structure
struct Foo {
int whatever;
int whatever2;
...
};
And I have this type of array
Foo **array = new Foo*[128];
Then, to every pointer I assign new structure
for (int i = 0; i < 128; i++)
array[i] = new Foo;
Then, after a while I deallocate:
delete[] array;
How memory will be deallocated?
Only the space for pointers will be freed
Space for pointer + the objects pointed by those pointers themselves?
Your code leaks memory. You need to call delete once for every new call (assuming the new doesn't fail and either return NULL or throw bad_alloc). So, in this case, you'll need to have a similar loop to the one that calls array[i] = new Foo; that does delete array[i];
I think this is one of points in Scott Meyers book, Effective C++ have read long back. But basic idea is, to avoid memory leak when you use new. make sure to call delete as many times as new is called and map new with delete and new[] with delete[] accordingly. so in your case new is called 128 times in for loop and new[] is called once, so similarly delete should be called same way to array[i] 128 times and delete[] should be called once for array. Hope this helps.

Requesting a specific address for the new operator

Say that I want to allocate an array of ints.
int* array = new int[5];
and then later on assume I have 5 int pointers, all pointing to the 5 different integers of the array.
int* v1 = &array[0];
int* v2 = &array[1]; //etc..etc
Now that I have "remembered" the location of all the ints in the array, I would like to manage the elements as individual integers. So in theory if I then set my array pointer to NULL...
array = NULL;
I would in theory not have to worry, because all my v1 and v2 pointers are pointing to all the elements in the array. The problem then is say like I am done with v2. So I would like to delete v2 to free up those 4 bytes.
delete v2;
Unfortunately, when I try to do that, bad things happen. I assume because the memory allocation table says "Hey, you can't delete in that space because it currently belongs to part of an int array!"
So thats fine, I would then like to say
delete [] array;
but if I do that, I want to make sure that when I do...
int* v1 = new int;
I want to guarantee that the newly allocated integer was created at the address of array[0]. So is there a way to specify where a new value is created? Or can I somehow control the memory list?
I've attempted to use the placement operator by calling something like...
int* v1 = new((void*)&array[0]) int;
but then when I delete the array with the delete operator and then attempt to access v1 by dereferenceing it... say
cout<<*v1;
I get a bunch of text to the screen that says "double free or corruption (fasttop): ...
I am using Ubuntu 11.04 and g++ compiler in codeblocks.
Also, just FYI, I have looked at Create new C++ object at specific memory address? and that is where I got the information about the placement operator, but it appears to not be working the way I need it to work.
#include <iostream>
using namespace std;
int main()
{
int *array = new int[20];
for(int i=0;i<4;i++)
{
array[i] = i;
}
int* a = new ((void*)&array[0]) int;
int* b = new ((void*)&array[1]) int;
int* c = new ((void*)&array[2]) int;
int* d = new ((void*)&array[3]) int;
int* e = new ((void*)&array[4]) int;
cout<<*a<<endl;
cout.flush();
delete[] array;
cout<<*a;
delete a;
delete b;
delete c;
delete d;
delete e;
return 0;
}
A correction:
int *v1 = array[0];
int *v2 = array[1];
should be
int *v1 = array;
int *v2 = array + 1;
Also, if you allocate new int[5], you can only free the memory for the entire array and not for individual elements.
"I want to guarantee that the newly allocated integer was created at the address of array[0]"
If that is the case, why should you go for a newly allocated integer? Just assign array to v1 as shown above.
Allocation of memory does not work the way you have used and neither can you release memory in the manner you are trying to.
A placement new "creates" an object at the given location by calling the constructor of the object but does not allocate memory and hence the memory used by placement new cannot be released by a delete. Memory should be pre-allocated before a call to placement new and the memory can be released based on how the pre-allocation was made.
Usage : Placement new.
Also, I found an example from a blog (not mine): Placement new
delete v2;
You should not delete elements individually allocated with placement new, release all the memory at one time when you are finished with it, like this delete [] array; (for a more detailed explanation).
And updating your code:
#include <iostream>
using namespace std;
int main()
{
int *array = new int[20];
for(int i=0;i<5;i++) // Still leaves garbage in rest of array
{
array[i] = i;
}
int* a = new (array) int;
// int* a = new(&array[0]) int;
int* b = new (array + 1) int;
int* c = new (array + 2) int;
int* d = new (array + 3) int;
int* e = new (array + 4) int;
cout << *a << " " << *b << " " << *c << " " << *d << " " << *e << endl;
delete[] array;
}
Couple of pointers:
1) cout.flush(); is unnecessary because std::endl calls flush() already.
2) I see no reason why placement new should be used here, take a look at this SO question to see reasons why you should use it. In your above example, int array[5]; and int* a = array; would be fine. Also, in a linked list the idea is that elements can be easily inserted and removed, if you allocate an array, you cannot delete the array and expect to be able to use the memory afterward (that would result in UB). So you have to choose between using an array or linked list, you can't have both (well, you could simulate a linked list to a certain extent).
3) Like I mentioned above, call delete [] array; after you are finished using the memory and do not dereference pointers into that memory or call delete on pointers into that memory once you have freed the memory.

Arrays & Pointers

Looking for some help with arrays and pointers and explanation of what I am trying to do.
I want to create a new array on the heap of type Foo* so that I may later assign objects that have been created else where to this array. I am having troubles understanding what I am creating exactly when I do something like the following.
Foo *(*f) = new Foo*[10];
Also once I have created my array how do I access each element for example.
(f + 9)->fooMember(); ??????
Thanks in advance.
Foo *(*f) = new Foo*[10];
The parentheses in the declaration are unnecessary, so this is the same as:
Foo **f = new Foo*[10];
In any case, the new Foo*[10] allocates space for ten Foo*s and leaves them uninitialized. It returns a pointer to the initial Foo* in the array (the zeroth element), which you assign to f.
To access elements of the array, you simply use subscripting:
f[0] = new Foo;
f[0]->fooMember();
Remember that anything you create using new[] must be freed once when you are done with it by calling delete[] on the pointer. For example:
delete[] f;
This does not delete the elements pointed to by the Foo*s in the array. If you create Foo objects using new, you must delete them before you delete the array. For example, to free the element we created above:
delete f[0];
You can create an array of pointers using the following code:
Foo** f = new Foo*[10];
Then access the elements with:
f[9]->fooMember();
Be sure to clean up afterwards:
delete[] f;
Thanks.
When you have this situation, you might find the following code snippet useful:
First the initialization:
Foo** f = new Foo*[10];
for (int i = 0; i < 10; i++) {
f[i] = new Foo;
}
Then to access each element in the f array which is what you asked, but you won't be able to do so unless you allocate memory properly for each member by calling the constructor as done above:
f[9]->fooMember();
Finally, to keep things tidy and to prevent memory leaks:
for (int i = 0; i < 10; i++) {
delete f[i];
}
delete[] f;
Arrays and pointers aren't very C++ish. How about
std::vector<std::shared_ptr<Foo> > f;
f.push_back(std::make_shared<Foo>(whatever, arguments, you, need));
// ...
f[9]->fooMember();
// ...
No manual cleanup needed :-)