How does an allocator create and destroy an array? - c++

How does an allocator create and destroy and array, for example
int* someInt = someAllocator(3);
Where without the allocator it would just be
int* someInt = new int[3];
Where the allocator is responsible for create each element and ensuring the constructor will be called.
How is the internals for an allocator written without the use of new? Could someone provide and example of the function?
I do not want to just use std::vector as I am trying to learn how an allocator will create an array.

The problem of general memory allocation is a surprisingly tricky one. Some consider it solved and some unsolvable ;) If you are interested in internals, start by taking a look at Doug Lea's malloc.
The specialized memory allocators are typically much simpler - they trade the generality (e.g. by making the size fixed) for simplicity and performance. Be careful though, using general memory allocation is usually better than a hodge-podge of special allocators in realistic programs.
Once a block of memory is allocated through the "magic" of the memory allocator, it can be initialized at container's pleasure using placement new.
--- EDIT ---
The placement new is not useful for "normal" programming - you'd only need it when implementing your own container to separate memory allocation from object construction. That being said, here is a slightly contrived example for using placement new:
#include <new> // For placement new.
#include <cassert>
#include <iostream>
class A {
public:
A(int x) : X(x) {
std::cout << "A" << std::endl;
}
~A() {
std::cout << "~A" << std::endl;
}
int X;
};
int main() {
// Allocate a "dummy" block of memory large enough for A.
// Here, we simply use stack, but this could be returned from some allocator.
char memory_block[sizeof(A)];
// Construct A in that memory using placement new.
A* a = new(memory_block) A(33);
// Yup, it really is constructed!
assert(a->X == 33);
// Destroy the object, wihout freeing the underlying memory
// (which would be disaster in this case, since it is on stack).
a->~A();
return 0;
}
This prints:
A
~A
--- EDIT 2 ---
OK, here is how you do it for the array:
int main() {
// Number of objects in the array.
const size_t count = 3;
// Block of memory big enough to fit 'count' objects.
char memory_block[sizeof(A) * count];
// To make pointer arithmetic slightly easier.
A* arr = reinterpret_cast<A*>(memory_block);
// Construct all 3 elements, each with different parameter.
// We could have just as easily skipped some elements (e.g. if we
// allocated more memory than is needed to fit the actual objects).
for (int i = 0; i < count; ++i)
new(arr + i) A(i * 10);
// Yup, all of them are constructed!
for (int i = 0; i < count; ++i) {
assert(arr[i].X == i * 10);
}
// Destroy them all, without freeing the memory.
for (int i = 0; i < count; ++i)
arr[i].~A();
return 0;
}
BTW, if A had a default constructor, you could try call it on all elements like this...
new(arr) A[count];
...but this would open a can of worms you really wouldn't want to deal with.

I've written about it in my second example here:
How to create an array while potentially using placement new
The difference is that the t_allocator::t_array_record would be managed by the allocator rather than the client.

Related

dynamic memory allocation using malloc keyword in c++ [duplicate]

I have a question wrt malloc/realloc memory that will contain an array of class/struct (i tried both struct and class the issue remains) members that include std vectors. I know I can circumvent the problem by using new and std array container class. However, I'd like to better understand why the following little code crashes when I use realloc instead of malloc (as I encountered this problem in the context of transitioning a larger code project from C to C++). It also seems that I cannot necessarily set an initial size of a vector in a class/struct (some compilers allow some don't ..)- so what is a vector in a class - a comfortable pointer?
Thanks,
Kai
#include <stdlib.h>
#include <limits.h>
#include <float.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <sys/types.h>
#include <vector>
/* mpic++ -O3 -ffast-math -pedantic vec-alloc.cpp -o vec-alloc */
using namespace std;
class float_vector{
public:
double x;
double y;
double z;
float_vector() : x(0), y(0), z(0) {};
};
class voxel{
public:
float_vector x;
vector<double> y;
voxel() : x() {};
};
int main(){
int i;
double d =1.111;
voxel v0, *Comp, *Comp2;
/* dynamically allocate memory */
Comp= (voxel*)malloc(10*sizeof(voxel));
for(i=0;i<10;++i) Comp[i] = v0;
printf("malloc done\n");
/* dynamically re-allocate memory */
Comp2= (voxel*)malloc(sizeof(voxel));
printf("realloc done\n");
for(i=0;i<10;++i){
Comp2 =(voxel*)realloc(&Comp2[0], (i+1)*sizeof(voxel));
Comp2[i] = v0;
}
printf("realloc done\n");
for(i=0;i<10;++i) Comp[i].y.push_back(d);
for(i=0;i<10;++i) printf("%lf\n",Comp[i].y[0]);
for(i=0;i<10;++i) Comp2[i].y.push_back(d); // this crashes
for(i=0;i<10;++i) printf("%lf\n",Comp2[i].y[0]);
return 1;
}
If you use malloc() with non-POD classes, you must call constructors (via placement new) and destructors manually.
Using an object which was not constructed properly results in undefined behavior, which often means a crash when it comes to pointers.
Obviously, freeing a memory for object without a proper destruction of it causes UB too.
Your code must look like this:
MyClass *arr = (MyClass *) malloc(10 * sizeof (MyClass));
for (int i = 0; i < 10; i++)
new (arr + i) MyClass; // This line calls constructors
// Do something with the array here
for (int i = 0; i < 10; i++)
arr[i].~MyClass(); // This line calls destructors.
free(arr);
This requirement also means that you can't use realloc() with non-POD types, because it wont call destructors for the old array and contructors for the new one for you.
Manual reallocation code might look like this:
MyClass *new_ptr = (MyClass *) malloc(new_size * sizeof (MyClass));
for (int i = 0; i < new_size; i++)
new (new_ptr + i) MyClass((MyClass &&) old_ptr[i]);
for (int i = new_size; i < old_size; i++)
new (new_ptr + i) MyClass;
for (int i = 0; i < old_size; i++)
old_ptr[i].~MyClass();
free(old_ptr);
And please keep in mind that above code is not really exception-safe. If a constructor throws an exception and you catch it, then you want to be sure that you properly destruct objects which were constructed. Thanks #SteveJessop.
Now when you understand why malloc()/free() usually should be avoided in C++, I hope you'll return to a lot more safe new/delete, which do all that construction and destruction for you.
It's probably nothing to do with the realloc. Your code already has undefined behaviour when you do this near the start:
for(i=0;i<10;++i) Comp[i] = v0;
Comp[0] has never been initialized (since malloc returns uninitialized memory -- it cannot know what type you intend to use it for and so could not possibly initialize it even if it wanted to). Then your code attempts to assign to it. This is not permitted for complex types like vector.
Why is it not permitted? In the case of vector, because when you assign to a vector that already holds data, it needs to free the old data. If there's nothing to free then it would free nothing. But uninitialized memory might have any values at all, so it may well appear to vector that there is something which should be freed, that in fact is not a freeable pointer at all, let alone something that vector should be freeing as a consequence of that assignment. Without initialization, some class invariant along the lines of "this pointer data member is always either a null pointer or else is the address of some memory that is the vector's responsibility" is violated and so the vector code does not work.
Supposing that your code somehow makes it past this point, you still can't realloc memory containing a vector. From the point of view of the standard, this is because vector<double> is not a POD type, and so byte-by-byte copies of it (including that done by realloc) result in undefined behavior.
From the point of view of a particular implementation, we might ask ourselves what code the implementer might write, which would go wrong in the case that vectors are copied byte-for-byte. One hypothetical answer is that in some circumstances the vector could contain a pointer into its own body (as part of a so-called small vector optimization) [Edit: actually, I think a small vector optimization isn't possible within the standard for other reasons, but my general point is that because vectors are not POD, the implementer is free to use their creativity]. If the vector is relocated then this pointer no longer points into the vector's own body and so the class invariants are not satisfied, and the code no longer works. To give implementers freedom to write code like this, your freedom as a user of the class is limited, and you are not permitted to relocate a vector (or in general any non-POD type) by byte-wise copying.
/* dynamically allocate memory */
Comp= (voxel*)malloc(10*sizeof(voxel));
Comp is now a pointer to uninitialized memory.
for(i=0;i<10;++i) Comp[i] = v0;
This attempts to call Comp[i].operator=(v0), but Comp[i] is not a valid, initialized object. In a simple test/debug case, we may get lucky but in practice we'll get garbage and the vector will either try to free/use an invalid pointer.
That doesn't just mean you have to calloc() the memory instead, you can't make assumptions about what values an initialized object expects to find.
/* dynamically re-allocate memory */
Comp2= (voxel*)malloc(sizeof(voxel));
printf("realloc done\n");
Comp2 is now a pointer to a single voxel, and no "realloc" was done.
for(i=0;i<10;++i){
Comp2 =(voxel*)realloc(&Comp2[0], (i+1)*sizeof(voxel));
Comp2[i] = v0;
}
This is just bizzare. It starts with Comp2 pointing to a single voxel. Then you for some reason take the address of the first element (&Comp2[0]) rather than just using the address of the first element (Comp2), and you reallocate it to the same size. You then copy-assign v0 into the uninitialized memory at the last-but-one position:
Comp2 = [...uninit...]
for (i = 0
realloc(i + 1 == 1)
Comp2 = [...uninit...]
^-- v0
i++
realloc(i+1 == 2)
Comp2 = [.....v0.....][...uninit...]
^--v0
Short: You can't use malloc or calloc or realloc with non-pod objects. You might get away with it occasionally, but you are basically pointing a loaded shotgun at your foot.
It also seems that I cannot necessarily set an initial size of a vector in a class/struct
You can easily set the default size of a vector in a class, C++11 required (-std=c++11 or greater for gnu/clang compilers, VS2013 or higher)
#include <iostream>
#include <vector>
struct A {
std::vector<int> v = { 1, 2, 3 }; // default population
};
struct B {
std::vector<int> v;
B() : v(4) {}
};
int main() {
A a;
B b;
std::cout << a.v.size() << ", " << b.v.size() << "\n";
std::cout << "\n";
for (int v : a.v) { std::cout << v << "\n"; }
std::cout << "\n";
for (int v : b.v) { std::cout << v << "\n"; }
}
http://ideone.com/KA9fWB

How to deallocate a portion of a continuous memory block?

let's assume I have a structure MyStruct and i want to allocate a "big" chunk of memory like this:
std::size_t memory_chunk_1_size = 10;
MyStruct * memory_chunk_1 = reinterpret_cast <MyStruct *> (new char[memory_chunk_1_size * sizeof(MyStruct)]);
and because of the "arbitrary reasons" I would like to "split" this chunk of memory into two smaller chunks without; moving data, resizing the "dynamic array", deallocating/allocating/reallocating memory, etc.
so I am doing this:
std::size_t memory_chunk_2_size = 5; // to remember how many elements there are in this chunk;
MyStruct * memory_chunk_2 = &memory_chunk_1[5]; // points to the 6th element of memory_chunk_1;
memory_chunk_1_size = 5; // to remember how many elements there are in this chunk;
memory_chunk_1 = memory_chunk_1; // nothing changes still points to the 1st element.
Unfortunately, when I try to deallocate the memory, I'm encountering an error:
// release memory from the 2nd chunk
for (int i = 0; i < memory_chunk_2_size ; i++)
{
memory_chunk_2[i].~MyStruct();
}
delete[] reinterpret_cast <char *> (memory_chunk_2); // deallocates memory from both "memory_chunk_2" and "memory_chunk_1"
// release memory from the 1st chunk
for (int i = 0; i < memory_chunk_1_size ; i++)
{
memory_chunk_1[i].~MyStruct(); // Throws exception.
}
delete[] reinterpret_cast <char *> (memory_chunk_1); // Throws exception. This part of the memory was already dealocated.
How can I delete only a selected number of elements (to solve this error)?
Compilable example:
#include <iostream>
using namespace std;
struct MyStruct
{
int first;
int * second;
void print()
{
cout << "- first: " << first << endl;
cout << "- second: " << *second << endl;
cout << endl;
}
MyStruct() :
first(-1), second(new int(-1))
{
cout << "constructor #1" << endl;
print();
}
MyStruct(int ini_first, int ini_second) :
first(ini_first), second(new int(ini_second))
{
cout << "constructor #2" << endl;
print();
}
~MyStruct()
{
cout << "destructor" << endl;
print();
delete second;
}
};
int main()
{
// memory chunk #1:
std::size_t memory_chunk_1_size = 10;
MyStruct * memory_chunk_1 = reinterpret_cast <MyStruct *> (new char[memory_chunk_1_size * sizeof(MyStruct)]);
// initialize:
for (int i = 0; i < memory_chunk_1_size; i++)
{
new (&memory_chunk_1[i]) MyStruct(i,i);
}
// ...
// Somewhere here I decided I want to have two smaller chunks of memory instead of one big,
// but i don't want to move data nor reallocate the memory:
std::size_t memory_chunk_2_size = 5; // to remember how many elements there are in this chunk;
MyStruct * memory_chunk_2 = &memory_chunk_1[5]; // points to the 6th element of memory_chunk_1;
memory_chunk_1_size = 5; // to remember how many elements there are in this chunk;
memory_chunk_1 = memory_chunk_1; // nothing changes still points to the 1st element.
// ...
// some time later i want to free memory:
// release memory from the 2nd chunk
for (int i = 0; i < memory_chunk_2_size ; i++)
{
memory_chunk_2[i].~MyStruct();
}
delete[] reinterpret_cast <char *> (memory_chunk_2); // deallocates memory from both "memory_chunk_2" and "memory_chunk_1"
// release memory from the 1st chunk
for (int i = 0; i < memory_chunk_1_size ; i++)
{
memory_chunk_1[i].~MyStruct(); // Throws exception.
}
delete[] reinterpret_cast <char *> (memory_chunk_1); // Throws exception. This part of the memory was already dealocated.
// exit:
return 0;
}
This kind of selective deallocation is not supported by the C++ programming language, and is probably never going to be supported.
If you intend to deallocate individual portions of memory, those individual portions need to be individually allocated in the first place.
It is possible that a specific OS or platform might support this kind of behavior, but it would be with OS-specific system calls, not through C++ standard language syntax.
Memory allocated with malloc or new cannot be partially deallocate. Many heaps use bins of different sized allocations for performance and to prevent fragmentation so allowing partial frees would make such a strategy impossible.
That of course does not prevent you writing your own allocator.
The simplest way I could think of by means of standard c++ would follow this idiomatic code:
std::vector<int> v1(1000);
auto block_start = v1.begin() + 400;
auto block_end = v1.begin() + 500;
std::vector<int> v2(block_start,block_end);
v1.erase(block_start,block_end);
v1.shrink_to_fit();
If a compiler is intelligent enough to translate such pattern to the most efficient low level OS and CPU memory management operations, is an implementation detail.
Here's the working example.
Let's be honest: this is a very bad practice ! Trying to cast new and delete and in addition call yourself destructor between the two is an evidence of low-level manual memory management.
Alternatives
The proper way to manage dynamic memory structures in contiguous blocks in C++ is to use std::vector instead of manual arrays or manual memory management, and let the library proceed. You can resize() a vector to delete the unneeded elements. You can shrink_to_fit() to say that you no longer need the extra free capacity, although it's not guaranteed that unneeded memory is released.
The use of C memory allocation functions and in particular realloc() is to be avoided, as it is very error prone, and it works only with trivially copiable objects.
Edit: Your own container
If you want to implement your own special container and must allows this kind of dynamic behaviour, due to unusual special constraints, then you should consider writing your own memory management function that would manage a kind of "private heap".
Heap management is often implement via a linked list of free chunks.
One strategy could be to allocate a new chunk when there's no sufficient contiguous memory left in your private heap. You could then offer a more permissive myfree() function that reinserts a freed or partially freed chunk into that linked list. Of course, this requires to iterate through the linked list to find if the released memory is contiguous to any other chunk of free memory in the private heap, and merge the blocks if adjacent.
I see that MyStruct is very small. Another approach could then be to write a special allocation function optimised for small fixed size blocks. There is an example in Loki's small object library that is described in depth in "Modern C++ Design".
Finally, you could perhaps have a look at the Pool library of Boost, which also offers a chunk based approach.

Using malloc/realloc for array of classes/structs including std vector

I have a question wrt malloc/realloc memory that will contain an array of class/struct (i tried both struct and class the issue remains) members that include std vectors. I know I can circumvent the problem by using new and std array container class. However, I'd like to better understand why the following little code crashes when I use realloc instead of malloc (as I encountered this problem in the context of transitioning a larger code project from C to C++). It also seems that I cannot necessarily set an initial size of a vector in a class/struct (some compilers allow some don't ..)- so what is a vector in a class - a comfortable pointer?
Thanks,
Kai
#include <stdlib.h>
#include <limits.h>
#include <float.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <sys/types.h>
#include <vector>
/* mpic++ -O3 -ffast-math -pedantic vec-alloc.cpp -o vec-alloc */
using namespace std;
class float_vector{
public:
double x;
double y;
double z;
float_vector() : x(0), y(0), z(0) {};
};
class voxel{
public:
float_vector x;
vector<double> y;
voxel() : x() {};
};
int main(){
int i;
double d =1.111;
voxel v0, *Comp, *Comp2;
/* dynamically allocate memory */
Comp= (voxel*)malloc(10*sizeof(voxel));
for(i=0;i<10;++i) Comp[i] = v0;
printf("malloc done\n");
/* dynamically re-allocate memory */
Comp2= (voxel*)malloc(sizeof(voxel));
printf("realloc done\n");
for(i=0;i<10;++i){
Comp2 =(voxel*)realloc(&Comp2[0], (i+1)*sizeof(voxel));
Comp2[i] = v0;
}
printf("realloc done\n");
for(i=0;i<10;++i) Comp[i].y.push_back(d);
for(i=0;i<10;++i) printf("%lf\n",Comp[i].y[0]);
for(i=0;i<10;++i) Comp2[i].y.push_back(d); // this crashes
for(i=0;i<10;++i) printf("%lf\n",Comp2[i].y[0]);
return 1;
}
If you use malloc() with non-POD classes, you must call constructors (via placement new) and destructors manually.
Using an object which was not constructed properly results in undefined behavior, which often means a crash when it comes to pointers.
Obviously, freeing a memory for object without a proper destruction of it causes UB too.
Your code must look like this:
MyClass *arr = (MyClass *) malloc(10 * sizeof (MyClass));
for (int i = 0; i < 10; i++)
new (arr + i) MyClass; // This line calls constructors
// Do something with the array here
for (int i = 0; i < 10; i++)
arr[i].~MyClass(); // This line calls destructors.
free(arr);
This requirement also means that you can't use realloc() with non-POD types, because it wont call destructors for the old array and contructors for the new one for you.
Manual reallocation code might look like this:
MyClass *new_ptr = (MyClass *) malloc(new_size * sizeof (MyClass));
for (int i = 0; i < new_size; i++)
new (new_ptr + i) MyClass((MyClass &&) old_ptr[i]);
for (int i = new_size; i < old_size; i++)
new (new_ptr + i) MyClass;
for (int i = 0; i < old_size; i++)
old_ptr[i].~MyClass();
free(old_ptr);
And please keep in mind that above code is not really exception-safe. If a constructor throws an exception and you catch it, then you want to be sure that you properly destruct objects which were constructed. Thanks #SteveJessop.
Now when you understand why malloc()/free() usually should be avoided in C++, I hope you'll return to a lot more safe new/delete, which do all that construction and destruction for you.
It's probably nothing to do with the realloc. Your code already has undefined behaviour when you do this near the start:
for(i=0;i<10;++i) Comp[i] = v0;
Comp[0] has never been initialized (since malloc returns uninitialized memory -- it cannot know what type you intend to use it for and so could not possibly initialize it even if it wanted to). Then your code attempts to assign to it. This is not permitted for complex types like vector.
Why is it not permitted? In the case of vector, because when you assign to a vector that already holds data, it needs to free the old data. If there's nothing to free then it would free nothing. But uninitialized memory might have any values at all, so it may well appear to vector that there is something which should be freed, that in fact is not a freeable pointer at all, let alone something that vector should be freeing as a consequence of that assignment. Without initialization, some class invariant along the lines of "this pointer data member is always either a null pointer or else is the address of some memory that is the vector's responsibility" is violated and so the vector code does not work.
Supposing that your code somehow makes it past this point, you still can't realloc memory containing a vector. From the point of view of the standard, this is because vector<double> is not a POD type, and so byte-by-byte copies of it (including that done by realloc) result in undefined behavior.
From the point of view of a particular implementation, we might ask ourselves what code the implementer might write, which would go wrong in the case that vectors are copied byte-for-byte. One hypothetical answer is that in some circumstances the vector could contain a pointer into its own body (as part of a so-called small vector optimization) [Edit: actually, I think a small vector optimization isn't possible within the standard for other reasons, but my general point is that because vectors are not POD, the implementer is free to use their creativity]. If the vector is relocated then this pointer no longer points into the vector's own body and so the class invariants are not satisfied, and the code no longer works. To give implementers freedom to write code like this, your freedom as a user of the class is limited, and you are not permitted to relocate a vector (or in general any non-POD type) by byte-wise copying.
/* dynamically allocate memory */
Comp= (voxel*)malloc(10*sizeof(voxel));
Comp is now a pointer to uninitialized memory.
for(i=0;i<10;++i) Comp[i] = v0;
This attempts to call Comp[i].operator=(v0), but Comp[i] is not a valid, initialized object. In a simple test/debug case, we may get lucky but in practice we'll get garbage and the vector will either try to free/use an invalid pointer.
That doesn't just mean you have to calloc() the memory instead, you can't make assumptions about what values an initialized object expects to find.
/* dynamically re-allocate memory */
Comp2= (voxel*)malloc(sizeof(voxel));
printf("realloc done\n");
Comp2 is now a pointer to a single voxel, and no "realloc" was done.
for(i=0;i<10;++i){
Comp2 =(voxel*)realloc(&Comp2[0], (i+1)*sizeof(voxel));
Comp2[i] = v0;
}
This is just bizzare. It starts with Comp2 pointing to a single voxel. Then you for some reason take the address of the first element (&Comp2[0]) rather than just using the address of the first element (Comp2), and you reallocate it to the same size. You then copy-assign v0 into the uninitialized memory at the last-but-one position:
Comp2 = [...uninit...]
for (i = 0
realloc(i + 1 == 1)
Comp2 = [...uninit...]
^-- v0
i++
realloc(i+1 == 2)
Comp2 = [.....v0.....][...uninit...]
^--v0
Short: You can't use malloc or calloc or realloc with non-pod objects. You might get away with it occasionally, but you are basically pointing a loaded shotgun at your foot.
It also seems that I cannot necessarily set an initial size of a vector in a class/struct
You can easily set the default size of a vector in a class, C++11 required (-std=c++11 or greater for gnu/clang compilers, VS2013 or higher)
#include <iostream>
#include <vector>
struct A {
std::vector<int> v = { 1, 2, 3 }; // default population
};
struct B {
std::vector<int> v;
B() : v(4) {}
};
int main() {
A a;
B b;
std::cout << a.v.size() << ", " << b.v.size() << "\n";
std::cout << "\n";
for (int v : a.v) { std::cout << v << "\n"; }
std::cout << "\n";
for (int v : b.v) { std::cout << v << "\n"; }
}
http://ideone.com/KA9fWB

Dynamic allocation with C++'s "placement new"

The question: How to use "placement new" for creating an array with dynamic size? or more specifically, how to allocate memory for array elements from a pre-allocated memory.
I am using the following code:
void* void_array = malloc(sizeof(Int));
Int* final_array = new(void_array) Int;
This guarantees that the final_array* (the array pointer) is allocated from the place that is reserved by void_array*. But what about the final_array elements? I want them to be allocated from a pre-allocated memory as well.
P.S: I have to say that I'm using some API that gives me some controls over a tile architecture. There is a function that works exactly like malloc, but also have other features, e.g. lets you control the properties of the allocated memory. So, what i basically need to do, is to use that malloc-like function to allocate memory with my desired properties (e.g. from which memory bank, to be cached where and etc.)
First off, let's make sure we all agree on the separation of memory allocation and object construction. With that in mind, let's assume we have enough memory for an array of objects:
void * mem = std::malloc(sizeof(Foo) * N);
Now, you cannot use placement array-new, because it is broken. The correct thing to do is construct each element separately:
for (std::size_t i = 0; i != N; ++i)
{
new (static_cast<Foo*>(mem) + i) Foo;
}
(The cast is only needed for the pointer arithmetic. The actual pointer required by placement-new is just a void pointer.)
This is exactly how the standard library containers work, by the way, and how the standard library allocators are designed. The point is that you already know the number of elments, because you used it in the initial memory allocation. Therefore, you have no need for the magic provided by C++ array-new, which is all about storing the array size somewhere and calling constructors and destructors.
Destruction works in reverse:
for (std::size_t i = 0; i != N; ++i)
{
(static_cast<Foo*>(mem) + i)->~Foo();
}
std::free(mem);
One more thing you must know about, though: Exception safety. The above code is in fact not correct unless Foo has a no-throwing constructor. To code it correctly, you must also store an unwind location:
std::size_t cur = 0;
try
{
for (std::size_t i = 0; i != N; ++i, ++cur)
{
new (static_cast<Foo*>(mem) + i) Foo;
}
}
catch (...)
{
for (std::size_t i = 0; i != cur; ++i)
{
(static_cast<Foo*>(mem) + i)->~Foo();
}
throw;
}
Instead of using a custom malloc, you should overwrite operator new() and use it. This is not operator new; there is a function actually called operator new(), confusing as it may seem, which is the function used by the normal (non-placement) operator new in order to get raw memory upon which to construct objects. Of course, you only need to overwrite it if you need special memory management; otherwise the default version works fine.
The way to use it is as follows, asuming your array size will be size:
Int* final_array = static_cast<Int*>(size == 0 ? 0 : operator new(sizeof(Int) * size));
Then you can construct and destroy each element independently. For instance, for element n:
// Create
new(final_array + n) Int; // use whatever constructor you want
// Destroy
(final_array + n)->~Int();

Better variant of getting the output dynamically-allocated array from the function?

Here is two variants. First:
int n = 42;
int* some_function(int* input)
{
int* result = new int[n];
// some code
return result;
}
int main()
{
int* input = new int[n];
int* output = some_function(input);
delete[] input;
delete[] output;
return 0;
}
Here the function returns the memory, allocated inside the function.
Second variant:
int n = 42;
void some_function(int* input, int* output)
{
// some code
}
int main()
{
int* input = new int[n];
int* output = new int[n];
some_function(input, output);
delete[] input;
delete[] output;
return 0;
}
Here the memory is allocated outside the function.
Now I use the first variant. But I know that many built-in c++ functions use the second variant.
The first variant is more comfortable (in my opinion). But the second one also has some advantages (you allocate and delete memory in the same block).
Maybe it's a silly question but what variant is better and why?
Third variant
const int n = 42;
template<class It1, class It2>
void some_function(It1 First, It1 Last, It2 output)
{
// some code
}
void main()
{
std::vector<int> input(n);
std::vector<int> output(n);
some_function(input.begin(), input.end(), output.begin());
}
I think second variant is better, because you have "balanced responsibility over pointer". That makes code more readable, because you see where you allocate and where you free your memory.
If you want to use first variant, I'd suggest you to make dual funnction some_function_free(). As for malloc/free, new/delete, new[]/delete[], etc. Even that it will do simple delete[], by using this you'll save time when you'll want to change the way you allocate memory.
Neither variant is preferred C++ style, especially in the presence of exceptions. If an exception is thrown somewhere (either in the allocation of output or in the body of some_function) one or both of your dynamically allocated arrays will leak memory. The preferred way is to use the Resource Allocation Is Initialization (RAII) concept. Safe C++ code uses objects to acquire resources. Their destructors free those resources. As the stack unwinds from an exception, any resources acquired to that point are safely released.
In the case of dynamically allocated arrays, that means std::vector. If it doesn't adversely affect your performance (profile it if you're worried), you can even return one by value.
// don't need the global variable anymore
std::vector<int> some_function(std::vector<int> &input)
{
std::vector<int> result;
// do something
return result;
}
int main() // main returns int, not void
{
std::vector<int> input;
// insert some values
std::vector<int> output = some_function(input);
return 0;
}
No more need to worry about who is responsible for allocating and freeing memory. Your code becomes clearer and exception-safe.
Generally speaking, it's better for functions not to heap-allocate and return objects, if practicable. It creates ownership issues, and complicates the interface (the caller has to know how to manage the lifespan of the returned object). It also puts more pressure on the memory allocator, which can in turn create thread contention, and denies the caller the opportunity to avoid this cost by allocating space for things more judiciously.
There's another benefit to the second one in that it does not require heap allocation. You can call the code using stack allocated memory only:
int main()
{
int input[10];
int output[10];
some_function(input, output);
}