c++ - 如何在 C++ 中手动初始化 std::list 的对象? class的指针有member list<>,不能new怎么办?

标签 c++ constructor std stdvector stdlist

假设这是一个 C++ 中的结构/类

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++ 区分内存和内存中的对象。您正在使用 malloc 分配内存或 calloc ,但您并未在分配的内存中创建任何对象。

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

new(pointer) MyClass /*initializer*/;

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

MyClass my_class /*initializer*/;

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

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


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

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

或者不这样做,而是将指针保存为 void*没有任何 Actor 暗示你它实际上并不指向一个对象,而只是内存。

你仍然可以通过 void*指向 placement-new 和 placement-new 的指针实际上会返回一个指向新对象的正确类型的指针(在某些特定情况下,您实际上需要使用此指针):

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

您还应该避免使用 malloccalloc之类的。 C++ 有自己的内存分配函数,称为(令人困惑的)operator new .它的用法类似于 malloc (像 calloc 那样将内存初始化为零是没有用的,因为 placement-new 中的初始化程序可以和/或将这样做):

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

及其 free模拟是:

operator delete(pointer);

它仍然只是分配内存,并没有像 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.

你不应该使用从 new 返回的原始指针, malloc或类似的首先拥有指针。 std::unique_ptr默认情况下具有正确的所有权语义,不需要您采取进一步的行动。

关于c++ - 如何在 C++ 中手动初始化 std::list 的对象? class的指针有member list<>,不能new怎么办?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59339117/

相关文章:

c++ - 如何在 QString.arg() 中使用我的枚举?

c++ - 在循环中跟踪当前和先前的变量

c++ - 适用于 Win32 和 WinCE 平台的线程

c++ - 如何使用 vector 默认构造函数?

c# - 是在再水化时调用的对象构造函数

c++ - 避免 std::list 中的指针

C++11 线程队列

c++ - 为什么 Clang 优化掉 x * 1.0 而不是 x + 0.0?

c++ - 将指向数据成员的指针传递给基类构造函数是否安全?

c++ - 如何创建 std::tuple 的别名?