Reputation: 13416
I have a class that is described that way :
class Foo {
int size;
int data[0];
public:
Foo(int _size, int* _data) : size(_size) {
for (int i = 0 ; i < size ; i++) {
data[i] = adapt(_data[i]);
}
}
// Other, uninteresting methods
}
I cannot change the design of that class.
How can I create an instance of that class ? Before calling the constructor, I have to make it reserve enough memory to store its data, so it has to be on the heap, not on the stack. I guess I want something like
Foo* place = static_cast<Foo*>(malloc(sizeof(int) + sizeof(int) * size));
*place = new Foo(size, data); // I mean : "use the memory allocated in place to do your stuff !"
But I can't find a way to make it work.
EDIT : as commentators have noticed, this is not a very good overall design (with non-standards tricks such as data[0]
), alas this is a library I am forced to use...
Upvotes: 8
Views: 961
Reputation: 25641
I think a good C++ solution is to get raw memory with new and then use placement new to embed your class into it.
getting raw memory works like this:
Foo *f = static_cast<Foo *>(operator new(sizeof(Foo));
constructing the object in received memory works like this:
new (f) Foo(size, data); // placement new
remember that this also means that you have to manually clean up the place.
f->~Foo(); // call the destructor
operator delete(f); // free the memory again
My personal opinion is, that it is bad to use malloc
and free
in newly written C++ code.
Upvotes: 1
Reputation: 10688
You could malloc
the memory for the object and then use a placement new
to create the object in the previously allocated memory :
void* memory = malloc(sizeof(Foo) + sizeof(int) * size);
Foo* foo = new (memory) Foo(size, data);
Note that in order to destroy this object, you can't use delete
. You would have to manually call the destructor and then use free
on the memory allocated with malloc
:
foo->~Foo();
free(memory); //or free(foo);
Also note that, as @Nikos C. and @GManNickG suggested, you can do the same in a more C++ way using ::operator new
:
void* memory = ::operator new(sizeof(Foo) + sizeof(int) * size);
Foo* foo = new (memory) Foo(size, data);
...
foo->~Foo();
::operator delete(memory); //or ::operator delete(foo);
Upvotes: 10
Reputation: 71989
You have a library that does this thing but doesn't supply a factory function? For shame!
Anyway, while zakinster's method is right (I'd directly call operator new instead of newing an array of chars, though), it's also error-prone, so you should wrap it up.
struct raw_delete {
void operator ()(void* ptr) {
::operator delete(ptr);
}
};
template <typename T>
struct destroy_and_delete {
void operator ()(T* ptr) {
if (ptr) {
ptr->~T();
::operator delete(ptr);
}
}
};
template <typename T>
using dd_unique_ptr = std::unique_ptr<T, destroy_and_delete<T>>;
using FooUniquePtr = dd_unique_ptr<Foo>;
FooUniquePtr CreateFoo(int* data, int size) {
std::unique_ptr<void, raw_delete> memory{
::operator new(sizeof(Foo) + size * sizeof(int))
};
Foo* result = new (memory.get()) Foo(size, data);
memory.release();
return FooUniquePtr{result};
}
Yes, there's a bit of overhead here, but most of this stuff is reusable.
Upvotes: 8
Reputation: 1689
If you really want to be lazy simply use a std::vector<Foo>
. It will use more space (I think 3 pointers instead of 1) but you get all the benefits of a container and really no downsides if you know it is never going to change in size.
Your objects will be movable given your definition so you can safely do the following to eliminate reallocation of the vector during initial fill...
auto initialFooValue = Foo(0, 0)
auto fooContainer = std::vector<Foo>(size, initialFooValue);
int i = 0;
for (auto& moveFoo : whereverYouAreFillingFrom)
{
fooContainer[i] = std::move(moveFoo);
++i;
}
Since std::vector is contiguous you can also just memcopy into it safely since your objects are trivially-copyable.
Upvotes: 1