使用新的展示位置

时间:2012-07-24 00:34:21

标签: c++

以下代码适合我。这怎么可行?这段错误不是吗?

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
}

4 个答案:

答案 0 :(得分:3)

  1. 第二个语句是潜在的UB(您使用buffer作为100 float的后备存储,它们肯定比100 char更多的内存。尽管如此,我对UB并不完全确定,因为标量类型的默认操作new会使它们保持未初始化状态,因此实际上没有触及该语句的内存。

  2. 当然,你可以做到,但这是一个无用的过度复杂,只需使用普通的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字节浮点数恰好适合,或者因为较早的newdelete已经映射了内存。即使它实际上没有立即发生段错误,也可能有一天崩溃或损坏堆或其他堆托管数据。更一般地说,你可以用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
};