如何在 C++ 中手动初始化 std::list 的对象? class的指针有一个成员列表<>,不能用new怎么办?

How to manually initialize std::list 's objects in C++? What to do if a pointer of class has a member list<>, can not use new?

假设这是 c++struct/class

struct MyClass{
  list<int> ls;
};

现在可能由于某些原因,无法初始化'MyClass'的指针,正在手动分配内存

MyClass *pointer = calloc(1, sizeof(MyClass));
pointer->ls.push_back(123); // <----- this line causes core dump

尽管它可以像这样使用纯 C++ 方法正常工作:-

MyClass *pointer = new MyClass;
pointer->ls.push_back(123);// All good, no problem

那么std::list中有什么功能可以解决这个问题吗?

我尝试用 std::vector 做同样的事情,因为当我使用 calloc()

时没有问题
struct MyClass{
  vector<int> ls;
};
MyClass *pointer = calloc(1, sizeof(MyClass));//using calloc
pointer->ls.push_back(123); // All Good

但是在使用 malloc 执行此操作时:-

struct MyClass{
  vector<int> ls;
};
MyClass *pointer = malloc(1, sizeof(MyClass));//using malloc
pointer->ls.push_back(123); // Core dump :-(

C++ 区分内存和内存中的对象。您正在使用 malloccalloc 分配内存,但您没有在分配的内存中创建任何对象。

您可以使用 placement-new 表达式在分配的存储中手动创建对象:

new(pointer) MyClass /*initializer*/;

这会在 pointer 指向的存储位置创建一个新的 MyClass 对象。 /*initializer*/ 是对象的可选初始值设定项,与变量声明中的含义相同

MyClass my_class /*initializer*/;

您可能需要 #include<new> 使用我在上面使用的新布局形式,并且您需要确保分配的内存块足够大并且与 MyClass 对象类型充分对齐.

使用指针就好像它指向一个对象,即使 none 是在存储位置创建的,也会导致未定义的行为,您正在观察到这一点。请注意,任何(甚至是基本的)类型技术上都是如此。将来可能会发生变化,以允许至少在使用时隐式创建普通类型(或某些类似类别),但对于非普通 class 类型(例如标准容器),这肯定不会改变。


还要注意 malloccalloc return void*,它们在 C++ 中不能隐式转换为不同的指针类型。您需要明确地转换它:

MyClass *pointer = static_cast<MyClass*>(malloc(sizeof(MyClass)));

或者不这样做,而是将指针保存为 void*,不进行任何转换以暗示您它实际上并不指向对象,而只是指向内存。

您仍然可以将那个 void* 指针传递给 placement-new 并且 placement-new 实际上会 return 您是一个指向新对象的正确类型的指针(有一些特定的实际上需要使用此指针的情况:

void *mem_ptr = malloc(sizeof(MyClass));
auto obj_ptr = new(mem_ptr) MyClass /*initializer*/;

您还应避免使用 malloccalloc 等。 C++ 有自己的内存分配函数,称为(令人困惑的)operator new。它像 malloc 一样使用(像 calloc 那样将内存初始化为零是没有用的,因为 placement-new can and/or 中的初始化程序会这样做):

void* pointer = operator new(sizeof(MyClass));

free 类似物是:

operator delete(pointer);

它仍然只是分配内存,并没有像 placement new 那样创建对象。


非placement new表达式new MyClass;分配内存(通过调用operator new创建一个对象就好像placement-new形式如上所述。


虽然你不需要为所有这些操心,因为你可以只使用智能指针并在以后初始化它,如果你需要的话:

std::unique_ptr<MyClass> ptr; // No memory allocated or object created

ptr = std::make_unique<MyClass>(/*constructor arguments*/); // Allocates memory and creates object

// Object is automatically destroyed and memory freed once no `std::unique_ptr` references the object anymore.

您首先不应使用 return 从 newmalloc 或类似的原始指针作为拥有指针。 std::unique_ptr 默认情况下具有正确的所有权语义,不需要您进行进一步的操作。