如果我没有修改参数构造函数中的任何static
变量,那么下面是模拟new T[N] (x,y);
(带参数的新数组)的正确方法吗?
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;
}
用途为,
struct A
{
A () {} // default
A (int i, int j) {} // with arguments
};
int main ()
{
A *p = new(A(1,2)) A[10]; // instead of new A[10](1,2)
}
我建议
std::vector<A> v(10, A(1,2));
我意识到这并不能真正解决数组的问题。你可以使用
p = &v[0];
因为该标准保证了连续存储。不过,调整矢量的大小要非常小心,因为这可能会使p 无效
我检查了boost::array<>(它适用于C风格的数组),但它没有定义构造函数。。。
这不好。您正在将对象复制到未初始化的内存中,而没有调用正确的复制语义。
只要你只处理POD,这就没问题。但是,当使用非POD的对象(例如A
)时,需要采取预防措施。
除此之外,operator new
不能以这种方式使用。正如Alexandre在评论中指出的那样,数组不会正确初始化,因为C++在调用operator new
之后会调用所有元素的构造函数,从而覆盖值:
#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 ctorn"; }
A() : x(0) { std::cout << "default ctorn"; }
A(const A& other) : x(other.x) { std::cout << "copy ctorn"; }
};
int main() {
A *p = new(A(42)) A[2];
for (unsigned i = 0; i < 2; ++i)
std::cout << p[i].x << std::endl;
}
这产生:
int ctor
copy ctor
copy ctor
default ctor
default ctor
0
0
…不是想要的结果。
这不好-如果typename T
有这样的对象(在您的示例中,struct A
确实有一个),C++将调用这些对象非平凡的默认构造函数,这将导致在已经占用的内存中重建对象。
一个合适的解决方案是使用std::vector
(推荐)或调用::operator new[]
来分配内存,然后使用placement new调用构造函数,并处理异常(如果有)。
您应该考虑到operator new[]
可能会被调用,要求获得比裸量sizeof(T) * n
更多的内存。
可能需要这个额外的内存,因为C++必须知道在delete[] p;
的情况下要销毁多少对象,但它不能可靠地使用new p[sz]
分配的内存块大小来推断这个数字,因为内存可能被要求给自定义内存管理器,所以(例如,您的情况)无法仅通过知道指针来知道分配了多少内存。
这也意味着,您提供已初始化对象的尝试将失败,因为实际返回到应用程序的数组可能不会从您从自定义operator new[]
返回的地址开始,因此初始化可能会错位。
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也可以这样写,这取决于您为其构建的平台:
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);
}