我正在玩动态大小内存池的想法,然后玩,我最终得到了一些我确定会失败但却没有的代码。这是代码:
#include <iostream>
using namespace std;
struct largeStruct
{
largeStruct()
{
X = 123456789;
Y = 987654321;
str = "Hy! Here I am, a c string, out in the wild c++, the place where your pointers dangle and your friends play with your privates";
}
unsigned long long X;
unsigned long long Y;
char* str;
};
int main()
{
void* ptr = new unsigned char[sizeof(largeStruct)];
largeStruct a;
*((largeStruct*)ptr) = a;
cout << "Size of data: " << sizeof(largeStruct) << endl;
cout << "Data: " << endl;
cout << ((largeStruct*)ptr)->X << endl
<< ((largeStruct*)ptr)->Y << endl
<< ((largeStruct*)ptr)->str << endl
<< endl;
delete[] ptr;
}
适用于我的电脑(Windows 8,MSVC Express 2012)。再加上一些,我认为,虽然是黑客,但它有一定道理。 内存中的数组是这样的:
===================================
... || a0 || a1 || a2 || ...
===================================
因此,当您尝试存储大于某个数组成员的值时,它会访问侧面的内存。因此,尝试存储3个块大小的值将起作用,并以此结束:
====================================
... || data data data data || ...
====================================
那么,这是危险的,还是某种模糊无害的黑客?
答案 0 :(得分:4)
§3.8...任何指向对象将要或所在的存储位置的指针 可以使用,但只能以有限的方式使用指针,就像指针的类型为void *一样, 定义明确。这样的指针可以被解除引用,但是所得到的左值可以仅以有限的方式使用,如下所述。如果出现以下情况,该程序的行为未定义:
- 指针用作static_cast(5.2.9)的操作数(除非转换为void *,或者转换为void *,然后转换为char *或unsigned char *)
和
§3.9T类对象的对象表示是由T类对象占用的N个无符号char对象的序列,其中N等于sizeof(T)。
和
§3.10/ 10如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:
- char或unsigned char类型。
这些非常混乱,但似乎把你的指针位称称为合法。但是,您在一个尚未构造的非对象的对象上调用赋值运算符。最好的解决方法是这样的:
std::allocator<largeStruct> al;
largeStruct a;
unsigned char* ptr = new char[sizeof(largeStruct)]; //allocate memory
al.construct((largeStruct*)ptr, a); //call the copy constructor
....
al.destroy((largeStruct*)ptr); //destroy the object
delete[] ptr; //deallocate memory
std::allocator
是所有C ++标准容器默认使用的标准分配器。 allocate
和deallocate
只需分别致电new char[]
和delete[]
。 construct
通过放置new来构造对象,destroy
通过手动调用析构函数来破坏它。你可以在一行代码中自己做两件事,但使用分配器是更好的做法。
或者,不是构造默认构造的本地实例的副本,而是使用largeStruct
al.construct((largeStruct*)ptr);
。