使用参数构造函数模拟new []

时间:2011-05-20 09:54:30

标签: c++ arrays constructor new-operator

如果我没有修改参数构造函数中的任何static变量,那么是否低于模拟new T[N] (x,y);(带参数的数组new)的正确方法?

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)
}

5 个答案:

答案 0 :(得分:5)

我建议

 std::vector<A> v(10, A(1,2));

我意识到这并没有真正解决数组的问题。 你可以用

 p = &v[0]; 

因为该标准保证了连续存储。但是要非常小心调整矢量大小,因为它可能使p

无效

我查看了boost :: array&lt;&gt; (它适应C样式数组),但它没有定义构造函数......

答案 1 :(得分:4)

不是确定。您正在将对象复制到未初始化的内存中,而不调用正确的复制语义。

只要你只与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 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;
}

这会产生:

int ctor
copy ctor
copy ctor
default ctor
default ctor
0
0

......不是理想的结果。

答案 2 :(得分:2)

那不行 - 如果typename T具有此类对象(在您的示例中struct A确实有一个),C ++将调用这些对象非平凡的默认构造函数,这将导致重构已占用的内存中的对象。

一个合适的解决方案是使用std::vector(推荐)或调用::operator new[]来分配内存,然后使用placement-new调用构造函数并处理异常(如果有的话)。

答案 3 :(得分:1)

您应该考虑operator new[]可能需要更多内存而不是sizeof(T) * n

可能需要这个额外的内存,因为在delete[] p;的情况下C ++必须知道要销毁多少个对象,但是它不能可靠地使用由new p[sz]分配的内存块的大小来推断这个数字,因为内存可能已经被问到自定义内存管理器(例如你的情况),只有通过知道指针才能知道分配了多少内存。

这也意味着您尝试提供已初始化的对象将失败,因为返回到应用程序的实际数组可能无法从您从自定义operator new[]返回的地址开始,因此初始化可能未对齐。 / p>

答案 4 :(得分:0)

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);
}