我们可以通过将连续的内存块转换为对象来创建对象。如果我们创建一个内存很少的对象,它在访问它时不会崩溃。但是它在超出范围时崩溃了。为什么?
class A
{
public:
int i;
};
void main(int argc, char * argv[])
{
{
vector<BYTE> v(1);
A* a = (A*)v.data();
a->i = 70000; // a's memory can't hold 4 bytes (int). Why no crash?
cout << a->i << endl; // Printed value - 70000. Why not crash here
} // Crashed here with heap corruption detected
cout << "End of scope\n";
}
最佳答案
从正式的角度来看,您只是在调用未定义行为,因为您正试图将 BYTE *
作为 A *
进行访问。根据严格的别名规则,编译器可以做任何它想做的事。
在现实世界中,这将取决于实现,并且很可能会给出正确的结果。在幕后,vector
的常见实现为其 data
成员使用分配的内存。这意味着:
- 它将针对任何类型正确对齐
- 实际分配的内存可能至少足够一个 int(由于对齐,它在 32 位系统上至少有 4 个字节,在 64 位系统上至少有 8 个字节)
- 您可以安全地更改分配内存的类型
这意味着这段代码不会崩溃也就不足为奇了,即使它是普通的未定义行为。
注意:除非在非常特殊的情况,并且有红色闪烁字体的通知,否则您不应该依赖代码的实现细节,因为它可能会在下一个版本的编译器中崩溃,或者只是如果您更改构建选项。
堆损坏只是一个警告,因为您的实现在它提供给您的最后一个字节之后放置了一个标记,并且发现该标记已被覆盖。但是从低层次的角度来看,你没有删除任何重要的东西——假设你的实现就像我的一样:-)
关于c++ - 类型转换时如何分配内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39245756/