Reputation: 6842
In some circumstances, my C++14 program needs a "block" of about 100 millions complex<float>
, which requires close to 1 GB of RAM. We can safely assume that the required memory will be available.
However allocating a new std::vector
is really slow, because the complex constructor is called 100 millions time. On my machine, the code requires around a full second to initialise the array.
By comparison, calling calloc()
, which initialises the allocated memory to zero, with mostly the same effect, will run in a very small number of milliseconds.
It turns out we don't even need this initialisation, because the complex in the large array will be populated shortly later from an external source. I am looking therefore at deferring the construction of the objects in that "block" to a later time, and then construct them directly from the external data source.
So my question is, is there a safe idiomatic and efficient C++ way to do that, perhaps using C++ move semantics along the way? If not, and we decide to simply malloc
the memory block, can we then simply reinterpret_cast
the memory block to a plain old C array of complex<float>
?
Thank you for helping
Jean-Denis Muys
Upvotes: 2
Views: 327
Reputation: 670
If you define the default constructor for the complex<float>
class as empty, which leaves the member variables uninitialized, then there shouldn't be any real difference between the two operations given that compiler optimizations are turned on.
Assuming the below definition for the complex
class.
template <typename T>
struct complex
{
complex() {}; // Empty constructor does nothing
T a, b;
};
The generated assembly for using vector
initialization with x86-64 gcc 6.2 and -O2 enabled is:
std::vector<complex<float>> v(100);
mov edi, 800
call operator new(unsigned long)
mov rdi, rax
call operator delete(void*)
And the generated assembly for manually calling malloc
and free
is:
auto v = malloc(100 * sizeof(complex<float>));
free(v);
mov edi, 800
call malloc
mov QWORD PTR [rsp+8], rax
mov rdi, QWORD PTR [rsp+8]
call free
As you can see, the vector
implementation no longer calls the constructor of complex<float>
for each element. The usage of vector
is more correct and readable, and also takes advantage of RAII which helps to prevent memory leaks.
Upvotes: 3
Reputation: 1313
I strongly suggest to stick to c++ and avoid manually managing the memory yourself.
The standard library should be enough. E.g.
std::vector< complex > my_vector;
// Reserve the necessary space without constructing anything
my_vector.reserve( 100'000'000);
// construct the elements when needed
populate( my_vector );
Upvotes: 2
Reputation: 5980
So your question is if you can use malloc()
. I used the same approach many years ago with my old C++ compiler and it worked. But at the end I had to call free()
instead of delete[]
. I think this is implementation-specific, so you should try it on your compiler.
Upvotes: 0