以下代码适合我。这怎么可行?这段错误不是吗?
char * buffer = new char[100];
float * in_buf = new(buffer) float[100];
我也有这样的课程:
class Item
{
public:
Item(int num)
{
u = new float[num];
v = new float[num];
}
float * u;
float * v;
//And many other variables
}
我想创建一个内存块并在其中分配v和u。这种方法安全吗?
class Item
{
public:
Item(int num)
{
buffer = new char[(sizeof(char)+2*sizeof(float))*num];
u = new (buffer) float[num];
v = new (buffer+sizeof(float)*num) float[num];
}
char * buffer;
float * u;
float * v;
//And many other variables
}
答案 0 :(得分:3)
第二个语句是潜在的UB(您使用buffer
作为100 float
的后备存储,它们肯定比100 char
更多的内存。尽管如此,我对UB并不完全确定,因为标量类型的默认操作new
会使它们保持未初始化状态,因此实际上没有触及该语句的内存。
当然,你可以做到,但这是一个无用的过度复杂,只需使用普通的new
。请注意,展示位置new
仅适用于少数极端情况,一般情况下不应使用。
答案 1 :(得分:3)
以下代码适合我。这怎么可行?这段错误不是吗?
char* buffer = new char[100];
float* in_buf = new(buffer) float[100];
“有效”是什么意思?由于这里的new
不需要初始化/构造有问题的数据类型,因此它们(必然)不会触发您计划用于它们的内存中的读取或写入。因此,您可能看不到段错误的一个原因是代码的有效地只执行此操作:
char* buffer = new char[100];
float* in_buf = reinterpret_cast<float*>(buffer);
如果您继续阅读或编写ala in_buf[99] = 2;
,您更有可能获得段错误但远非保证 - 可能是该地址的内存位于应用程序的虚拟地址空间中。例如,假设对一页内存的请求满足100个字符的请求,并且OS页面大小为> = 4096字节 - 1000个4字节浮点数恰好适合,或者因为较早的new
和delete
已经映射了内存。即使它实际上没有立即发生段错误,也可能有一天崩溃或损坏堆或其他堆托管数据。更一般地说,你可以用C ++做很多不安全的事情,它们实际上不会立即咬人....
这样安全吗?
buffer = new char[(sizeof(char)+2*sizeof(float))*num];
u = new (buffer) float[num];
v = new (buffer+sizeof(float)*num) float[num];
是(假设num的值是合理的),但是它毫无意义地复杂化(并且额外的角色毫无意义且积极混淆)。你可以这样做:
u = new float[2 * num];
v = &u[num];
答案 2 :(得分:1)
你的第一个问题中的问题可以通过一个很小的变化来说明,除非你并排比较代码,否则你看不到它:
char * buffer = new char[100];
float * in_buf = new(buffer) float[100]();
这给了我MSVS中的运行时堆损坏错误。
答案 3 :(得分:0)
正如提到的其他答案一样,第float * in_buf = new(buffer) float[100];
行将大部分数组放在buffer
的范围之外。它没有分裂,因为记忆还没有被触及。
如果你和v没有有意义的构造者(即他们被零初始化),那么新的位置没有意义并且不会像这样的东西一样清楚:
class Item
{
public:
Item(int num)
{
size_t buffer_size = sizeof(*buffer);
size_t u_size = sizeof(*u) * num;
size_t v_size = sizeof(*v) * num;
buffer = new char[buffer_size + u_size + v_size];
u = reinterpret_cast<float* >(buffer + buffer_size);
v = reinterpret_cast<float* >(buffer + buffer_size + u_size);
}
char * buffer;
float * u;
float * v;
//And many other variables
};
您是否需要拥有运行时num
参数?如果你可以侥幸逃脱,我建议将Item模板化为:
template <int NUM>
class Item
{
public:
Item() {}
char buffer[NUM];
float u[NUM];
float v[NUM];
//And many other variables
};