在C++ 11中,如何调用new并为对象保留足够的内存?

Fab*_*ien 8 c++ memory-management c++11

我有一个以这种方式描述的类:

class Foo {
    int size;
    int data[0];

public:
    Foo(int _size, int* _data) : size(_size) {
        for (int i = 0 ; i < size ; i++) {
            data[i] = adapt(_data[i]);
        }
    }

    // Other, uninteresting methods
}
Run Code Online (Sandbox Code Playgroud)

我无法改变那门课程的设计.

如何创建该类的实例?在调用构造函数之前,我必须保留足够的内存来存储其数据,因此它必须在堆上,而不是在堆栈上.我想我想要的东西

Foo* place = static_cast<Foo*>(malloc(sizeof(int) + sizeof(int) * size));
*place = new Foo(size, data);  // I mean : "use the memory allocated in place to do your stuff !"
Run Code Online (Sandbox Code Playgroud)

但我找不到办法让它发挥作用.

编辑:正如评论员所注意到的,这不是一个非常好的整体设计(使用非标准技巧data[0]),唉这是一个我不得不使用的库...

zak*_*ter 11

您可以malloc使用对象的内存,然后使用a placement new在先前分配的内存中创建对象:

void* memory = malloc(sizeof(Foo) + sizeof(int) * size);
Foo* foo = new (memory) Foo(size, data);
Run Code Online (Sandbox Code Playgroud)

请注意,为了销毁此对象,您无法使用delete.您必须手动调用析构函数,然后free在分配的内存上使用malloc:

foo->~Foo();
free(memory); //or free(foo);
Run Code Online (Sandbox Code Playgroud)

另请注意,正如@Nikos C.@GManNickG建议的那样,您可以使用以下更多C++方式执行相同的操作::operator new:

void* memory = ::operator new(sizeof(Foo) + sizeof(int) * size);
Foo* foo = new (memory) Foo(size, data);
...
foo->~Foo();
::operator delete(memory); //or ::operator delete(foo);
Run Code Online (Sandbox Code Playgroud)

  • 执行`malloc(sizeof(Foo)+ ...`而不是`sizeof(int)`会稍微安全一些.以防万一`Foo`将来会成为另一个成员. (3认同)
  • 你实际上可以避免使用malloc()并执行`void*memory = new char [sizeof(Foo)+ sizeof(int)*size];` (2认同)

Seb*_*edl 8

你有一个库来做这件事,但不提供工厂功能?耻辱!

无论如何,虽然zakinster的方法是正确的(虽然我直接调用operator new而不是新建一个chars数组),但它也容易出错,所以你应该把它包起来.

struct raw_delete {
  void operator ()(void* ptr) {
    ::operator delete(ptr);
  }
};

template <typename T>
struct destroy_and_delete {
  void operator ()(T* ptr) {
    if (ptr) {
      ptr->~T();
      ::operator delete(ptr);
    }
  }
};
template <typename T>
using dd_unique_ptr = std::unique_ptr<T, destroy_and_delete<T>>;

using FooUniquePtr = dd_unique_ptr<Foo>;

FooUniquePtr CreateFoo(int* data, int size) {
  std::unique_ptr<void, raw_delete> memory{
    ::operator new(sizeof(Foo) + size * sizeof(int))
  };
  Foo* result = new (memory.get()) Foo(size, data);
  memory.release();
  return FooUniquePtr{result};
}
Run Code Online (Sandbox Code Playgroud)

是的,这里有一些开销,但大部分内容都是可重用的.