C++ 为什么push#u back()会导致malloc()和#x27内的崩溃;教育数据?

C++ 为什么push#u back()会导致malloc()和#x27内的崩溃;教育数据?,c++,visual-c++,malloc,stdvector,C++,Visual C++,Malloc,Stdvector,为什么会崩溃?我确实发现malloc()不调用构造函数,所以我自己手动调用了它们,但它仍然崩溃,我不明白为什么 另外,我知道std::vector和new[]存在。不要告诉我使用vectors/new[]作为答案 struct MyStruct { vector<int> list; }; void make_crash(){ MyStruct *array = (MyStruct *)malloc(100*sizeof(MyStruct)); MyStruc

为什么会崩溃?我确实发现malloc()不调用构造函数,所以我自己手动调用了它们,但它仍然崩溃,我不明白为什么

另外,我知道std::vector和new[]存在。不要告诉我使用vectors/new[]作为答案

struct MyStruct {
    vector<int> list;
};
void make_crash(){
    MyStruct *array = (MyStruct *)malloc(100*sizeof(MyStruct));
    MyStruct element; // initialize element here since malloc() doesnt do it.
    array[0] = element; // copy, everything should be alright?
    array[0].list.push_back(1337); // nope, BANG!
    // The above line makes these:
    // First-chance exception at 0x7c970441 in test.exe: 0xC0000005: Access violation reading location 0xbaadf005.
    // First-chance exception at 0x00401cd0 in test.exe: 0xC0000005: Access violation reading location 0xbaadf00d.
    // Unhandled exception at 0x00401cd0 in test.exe: 0xC0000005: Access violation reading location 0xbaadf00d.
}
struct MyStruct{
向量表;
};
void make_crash(){
MyStruct*数组=(MyStruct*)malloc(100*sizeof(MyStruct));
MyStruct element;//在这里初始化元素,因为malloc()不这样做。
数组[0]=element;//复制,一切正常吗?
数组[0]。列表。向后推(1337);//不,砰!
//上列内容包括:
//test.exe中0x7c970441处的首次机会异常:0xC0000005:访问冲突读取位置0xbaadf005。
//test.exe中0x00401cd0处的首次机会异常:0xC0000005:访问冲突读取位置0xbaadf00d。
//test.exe中0x00401cd0处的未处理异常:0xC0000005:访问冲突读取位置0xbaadf00d。
}

行上的数组[0]=元素
您正在调用
数组[0]
操作符=
。由于
数组[0]
未初始化,因此这是未定义的行为。对尚未调用构造函数的对象调用任何方法或运算符,包括
operator=
,都是未定义的行为


要解决此问题,您需要使用placement new来调用
数组[0]
的构造函数,或者只使用
new
而不是
malloc
。除非您有充分的理由使用
malloc
,否则后者更可取(甚至更好:使用向量)。

这不是初始化元素的方式。正在对不存在的对象调用(隐式创建的)赋值运算符(调用vector的赋值运算符),这显然是个坏消息

您必须改用“新放置”:

new(array)MyStruct

对于阵列:


new(array)MyStruct[100]

当您分配给
MyStruct

array[0] = element;
首先有人试图破坏结构的旧成员,但没有,因为它们从未被构造过。轰

获取100个
MyStruct
s的最简单方法是使用另一个向量

vector<MyStruct>  v(100);
向量v(100);
无需使用
malloc

MyStruct *array = (MyStruct *)malloc(100*sizeof(MyStruct));
这就是你错的地方

array
不是指向一个或多个
MyStruct
对象的指针,而不管您为其指定了什么类型。
malloc
的返回值是一个
void*
。C++的规则不允许你从 Vult*/Cux>隐式地转换成其他类型,这就是为什么你必须在其中放置那个<代码>(MyStReT*)< /C> >。需要一个明确的演员应该告诉你,你正在做一些阴暗的事情

< C++的规则规定,如果您明确地将<代码>空白>代码>到某些<代码>类型*<代码>(在某些特定类型之外),这是合法的,如果 Value*/Cux>您所做的“CAST”最初是“代码>类型*<代码>,它本身被转换成Value*/Cuth>。这不是原因;这个
void*
来自
malloc
,从来不是
MyStruct*
。你在对编译器撒谎,因此引发了未定义的行为。因此发生了碰撞

如果你想要定义行为,那么你需要实际使用C++,而不是“你不能相信它不是C++”语言。例如:

void *block = malloc(100 * sizeof(MyStruct));
MyStruct* array = new(block) MyStruct[100];
注意这里完全没有强制转换操作

当然,删除此数组是一件痛苦的事情:

for(int i = 99; i >= 0; --i)
  array[i].~MyStruct();

free(block);
请注意,您必须按照与构建顺序相反的顺序向后销毁它们


想知道这些东西在内部是如何工作的。new[]是否会生成一些额外的内存来告诉我的CPU malloc没有的东西?为什么/什么/如何模仿它而没有新的[]?还是新的安置?如何用CPU的原始二进制代码编写它?有可能吗?新的[]到底在这里做什么

所有这些都依赖于实现。就语言而言,到底发生了什么是明确定义的。除其他外,Placement new将调用对象的构造函数。Array placement new将按从头到尾的顺序调用数组中所有对象的构造函数。如果其中一个抛出,那么它将对任何先前构造的对象调用析构函数,然后发出异常

确切地说,所做的事情取决于实现,并不比继承的实现方式更重要。显然,编译器会为它发出一些代码,但同样,发出的内容取决于实现

<>你如何“在原始二进制代码中写入CPU”是不可能的,只要你真的在写C++。要实现placement new,您必须能够调用类的构造函数。而且。。。好吧,这就是新安置的目的。您甚至不允许获取指向构造函数的成员指针(即使可以,成员指针的内容也依赖于实现,并且它们并不总是指向某个汇编函数的裸指针)。因此,如果没有特定于平台的陪审团操纵,甚至无法识别构造函数代码


通过查看生成的程序集以调用placement new,可以了解如何为特定系统执行此操作。但每个编译器上的情况都不一样。

你为什么要这样做?@K-ballo,因为我很蠢……如果我说我也是个白痴,我会得到额外的分数吗虽然被误导了,你的问题仍然很有趣。。。我只是想知道为什么会有人试图这么做。@K-ballo,为什么?真的,真的。。。生命的奥秘。有没有可能“破解”它,让它在没有新的东西的情况下工作?只是有兴趣…@新秀请记住,新位置和常规新位置是两件完全不同的事情。我认为没有任何黑客不是这样的