placement new在堆内存中创建对象数组

2019-02-22  本文已影响0人  DyadicQ

如果类(class)中我们指定了带参数的构造函数(constructor),那么一般在创建该对象类型的数组时是没法给定构造参数的,就是说无法调用到我们指定的构造函数,如下:

class Foo {
    public:
        Foo(int ID);
        int getId();
    private:
        int ID;
};

Foo::Foo(int ID) {
    this->ID = ID;
}

int Foo::getId() {
    return ID;
}
int main () {

Foo *foos = new Foo[10];  //错误,没有正确调用到构造函数

//...
 }  

我们可以在定义数组时直接初始化,这样可以给定构造参数,例如:

int ID1, ID2, ID3, .... , ID10;
Foo *foos = {
  new Foo(ID1),
  new Foo(ID2),
  ...
  new Foo(ID10)
};

这样可以,但是如果我们想要在堆中动态分配数组那怎么办呢?这里就要用到operator new[]函数(注意,这是函数,不是操作符),它的用法:operator new[] (size_t m)

如下:

void *raw = operator new[] (10 * sizeof(Foo));
Foo *foos  = static_cast<Foo*> (raw);
for (int i = 0; i < 10; i++) {
  new (&foos[i]) Foo (ID);    //注意这种用法,可以直接将数组中对应元素对象调用构造函数构造。
}

还有一种思路就是构建指针数组,然后调用构造函数构造:

void *raw = operator new[] (10 * sizeof(Foo*));
Foo **pfoos = static_cast<Foo**> (raw);
for (int i = 0; i < 10; i++) {
  pfoos[i] = new Foo(ID);
}

对比这两种方式,很有意思,尤其前一种方式的用法(这种方式叫做placement new)。
注意这种方式要手动释放内存,需要两步,第一步:

//与构造顺序相反
for (int i = 9; i >= 0; --i) {
  foos[i].~Foo();   
}

第二步:

//释放raw指针
operator delete[] raw;
上一篇 下一篇

猜你喜欢

热点阅读