Simulating new[] with argument constructor
If I am not modifying any static
variable inside the argument constructor, is below the proper way to simulate new T[N] (x,y);
(array new with arguments) ?
template<typename T>
void* operator new [] (size_t size, const T &value)
{
T* p = (T*) malloc(size);
for(int i = size / sizeof(T) - 1; i >= 0; i--)
memcpy(p + i, &value, sizeof(T));
return p;
}
Usage will be,
struct A
{
A () {} // default
A (int i, int j) {} // with argum开发者_JAVA百科ents
};
int main ()
{
A *p = new(A(1,2)) A[10]; // instead of new A[10](1,2)
}
I'd suggest
std::vector<A> v(10, A(1,2));
I realize that this doesn't really address the question for arrays. You could use
p = &v[0];
since the standard guarantees contiguous storage. Be very careful with resizing the vector though, because it could invalidate p
I checked boost::array<> (which adapts C style arrays), but it doesn't define constructors...
This isn’t OK. You are copying objects into uninitialised memory without invoking proper copy semantics.
As long as you’re only working with PODs, this is fine. However, when working with objects that are not PODs (such as your A
) you need to take precautions.
Apart from that, operator new
cannot be used in this way. As Alexandre has pointed out in the comments, the array won’t be initialised properly since C++ will call constructors for all elements after having called your operator new
, thus overriding the values:
#include <cstdlib>
#include <iostream>
template<typename T>
void* operator new [] (size_t size, T value) {
T* p = (T*) std::malloc(size);
for(int i = size / sizeof(T) - 1; i >= 0; i--)
new(p + i) T(value);
return p;
}
struct A {
int x;
A(int x) : x(x) { std::cout << "int ctor\n"; }
A() : x(0) { std::cout << "default ctor\n"; }
A(const A& other) : x(other.x) { std::cout << "copy ctor\n"; }
};
int main() {
A *p = new(A(42)) A[2];
for (unsigned i = 0; i < 2; ++i)
std::cout << p[i].x << std::endl;
}
This yields:
int ctor
copy ctor
copy ctor
default ctor
default ctor
0
0
… not the desired outcome.
That's not okay - C++ will call those objects non-trivial default constructors if typename T
has such (struct A
in your example does have one) and that would lead to reconstructing objects in memory already occupied.
An appropriate solution would be to use std::vector
(recommended) or call ::operator new[]
to allocate memory, then call constructors using placement-new and taking care of exceptions if any.
You should consider that operator new[]
may be called asking for more memory than the bare amount sizeof(T) * n
.
This extra memory is possibly needed because C++ must know how many object to destroy in case of delete[] p;
but it cannot reliably use the size of block of memory allocated by new p[sz]
to infer this number because the memory may have been asked to a custom memory manager so (e.g. your case) there is no way to know how much memory was allocated only by knowing the pointer.
This also means that your attempt to provide already-initialized objects will fail because the actually array returned to the application will potentially not start at the address you returned from your custom operator new[]
so that initialization could be misaligned.
template <typename myType> myType * buildArray(size_t numElements,const myType & startValue) {
myType * newArray=(myType *)malloc(sizeof(myType)*numElements);
if (NULL!=newArray) {
size_t index;
for (index=0;index<numElements;++index) {
new (newArray+index) myType(startValue);
}
}
return newArray;
}
template <typename myType> void destroyArray(size_t numElements,myType * oldArray) {
size_t index;
for (index=0;index<numElements;++index) {
(oldArray+index)->~myType();
}
free(oldArray);
}
A * p=newArray(10,A(1,2));
destroyArray(10,p);
destroyArray could also be written like this depending on the platform you are building for:
template <typename myType> void destroyArray(myType * oldArray) {
size_t numElements=malloc_size(oldArray)/sizeof(myType); //or _msize with Visual Studio
size_t index;
for (index=0;index<numElements;++index) {
(oldArray+index)->~myType();
}
free(oldArray);
}
精彩评论