如何在 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++ 区分内存和内存中的对象。您正在使用 malloc
或 calloc
分配内存,但您没有在分配的内存中创建任何对象。
您可以使用 placement-new 表达式在分配的存储中手动创建对象:
new(pointer) MyClass /*initializer*/;
这会在 pointer
指向的存储位置创建一个新的 MyClass
对象。 /*initializer*/
是对象的可选初始值设定项,与变量声明中的含义相同
MyClass my_class /*initializer*/;
您可能需要 #include<new>
使用我在上面使用的新布局形式,并且您需要确保分配的内存块足够大并且与 MyClass
对象类型充分对齐.
使用指针就好像它指向一个对象,即使 none 是在存储位置创建的,也会导致未定义的行为,您正在观察到这一点。请注意,任何(甚至是基本的)类型技术上都是如此。将来可能会发生变化,以允许至少在使用时隐式创建普通类型(或某些类似类别),但对于非普通 class 类型(例如标准容器),这肯定不会改变。
还要注意 malloc
和 calloc
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*/;
您还应避免使用 malloc
和 calloc
等。 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 从 new
、malloc
或类似的原始指针作为拥有指针。 std::unique_ptr
默认情况下具有正确的所有权语义,不需要您进行进一步的操作。
假设这是 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++ 区分内存和内存中的对象。您正在使用 malloc
或 calloc
分配内存,但您没有在分配的内存中创建任何对象。
您可以使用 placement-new 表达式在分配的存储中手动创建对象:
new(pointer) MyClass /*initializer*/;
这会在 pointer
指向的存储位置创建一个新的 MyClass
对象。 /*initializer*/
是对象的可选初始值设定项,与变量声明中的含义相同
MyClass my_class /*initializer*/;
您可能需要 #include<new>
使用我在上面使用的新布局形式,并且您需要确保分配的内存块足够大并且与 MyClass
对象类型充分对齐.
使用指针就好像它指向一个对象,即使 none 是在存储位置创建的,也会导致未定义的行为,您正在观察到这一点。请注意,任何(甚至是基本的)类型技术上都是如此。将来可能会发生变化,以允许至少在使用时隐式创建普通类型(或某些类似类别),但对于非普通 class 类型(例如标准容器),这肯定不会改变。
还要注意 malloc
和 calloc
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*/;
您还应避免使用 malloc
和 calloc
等。 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 从 new
、malloc
或类似的原始指针作为拥有指针。 std::unique_ptr
默认情况下具有正确的所有权语义,不需要您进行进一步的操作。