C++ 使用参数构造函数模拟新[]

C++ 使用参数构造函数模拟新[],c++,arrays,constructor,new-operator,C++,Arrays,Constructor,New Operator,如果我没有修改参数构造函数中的任何静态变量,则低于模拟新T[N](x,y)的正确方式(带有参数的新数组) 我建议 std::vector<A> v(10, A(1,2)); 因为标准保证了连续存储。但是,在调整向量大小时要非常小心,因为这可能会使p无效 我检查了boost::array(它适应C样式的数组),但它没有定义构造函数…这不好。您正在将对象复制到未初始化的内存中,而没有调用正确的复制语义 只要你只使用豆荚,这很好。但是,在处理非吊舱的对象(例如A)时,需要采取预防措施

如果我没有修改参数构造函数中的任何
静态
变量,则低于模拟
新T[N](x,y)的正确方式(带有参数的新数组)

我建议

 std::vector<A> v(10, A(1,2));
因为标准保证了连续存储。但是,在调整向量大小时要非常小心,因为这可能会使p无效

我检查了boost::array(它适应C样式的数组),但它没有定义构造函数…

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

只要你只使用豆荚,这很好。但是,在处理非吊舱的对象(例如
A
)时,需要采取预防措施

除此之外,
operator new
不能以这种方式使用。正如注释中所指出的,C++在调用了<代码>运算符new < /C>之后,将调用所有元素的构造函数,因此无法正确初始化数组,因此重写了以下值:

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

…不是期望的结果。

< P>你应该考虑<代码>运算符new []/Cord>可以要求比裸量<代码> sieOf(t)*n >更多的内存。

<>这个额外的内存可能是需要的,因为C++必须知道有多少对象要销毁,在<代码> DELL[]P;code>但它不能可靠地使用
new p[sz]
分配的内存块大小来推断此数字,因为内存可能已被请求到自定义内存管理器,因此(例如,您的案例)仅通过知道指针无法知道分配了多少内存


这也意味着您提供已初始化对象的尝试将失败,因为返回到应用程序的实际数组可能不会从您从自定义
运算符new[]返回的地址开始这样初始化可能会被错配。

< P>这是不好的。如果代码> >类型名T 有这样的代码(在例子中<代码>结构< < />代码>,这将导致在已经占用的内存中重建对象),C++将调用那些对象非平凡的默认构造函数。 一个合适的解决方案是使用
std::vector
(推荐)或调用
::operator new[]
来分配内存,然后使用placement new调用构造函数并处理异常(如果有)。

模板myType*构建数组(大小、常量myType和startValue){
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);
myType*newArray=(myType*)malloc(sizeof(myType)*numElements); if(NULL!=newArray){ 尺寸指数;
对于(index=0;index)您可以通过传入
const T&value
而不是
T value
T value…memcpy(…,&value,…)来避免一些复制
当然不是一个好主意。我认为这种方法是完全错误的。new的任何变体都不应该构造任何东西。它只返回一个要调用构造函数的地址。如果构造失败,您还需要提供一个匹配的
操作符delete
。但不,不要这样做。使用
std::vector
。如果这是可行的,为什么语言中还没有呢?@Alextandre,谢谢你指出。我没有在默认构造函数中放入调试:).1对于
放置new
。这是对
memcpy
的巨大改进。不,不要在
操作符new
中构造任何内容。它应该只返回一个地址,句号。@AlexandreC。不是在这个重载中。问题是在构造对象之后明确提出的,这是完全正确的。您考虑的是一个参数
>::运算符new
,这是一个完全不同的问题。@Konrad:placement new和NotRow new在其定义中也不构造任何内容。它们只返回对象应该构造的地址。如果您这样做(我怀疑这是可能的,因为您的对象将被默认构造的对象覆盖,可能会泄漏很多东西)如果你的<代码>操作符new < /Cord>会引发一个异常。@ Alxand Read。是的,但是它们是不同的。这个重载是完全不同的函数,只是恰好有相同的名称。这也构造了对象。C++没有限制,称过载。事实上,完全不同的是,C++已经定义了构造对象的重载:例如,考虑代码< new int(10)()
。这将创建一个由10个
T
类型的对象组成的C数组,并对它们进行初始化。请告诉我,这个代码在地球上比
std::vector
有什么优势?@Alexandre无论是出于习惯还是出于需要,在内存分配方面,有些人都是控制狂。我在这里使用了malloc,但它可能是任何其他内存分配locator.@Alexandre这些函数提供了新的类似[]的语义,同时提供了对对象构造的控制,而对象构造正是OP所要求的。并非所有数组问题都是要用STL回答的XY问题。
 p = &v[0]; 
#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
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);
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);
}