0

下面的代码对我有用。这怎么能行?这不会是段错误吗?

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

4 回答 4

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

  2. 当然,你可以做到,但这是一个无用的过度复杂化,只需使用普通的new. 请记住,放置new仅适用于少数极端情况,通常不应使用。

于 2012-07-24T00:40:00.780 回答
3

下面的代码对我有用。这怎么能行?这不会是段错误吗?

char* buffer = new char[100];
float* in_buf = new(buffer) float[100];  

“作品”是什么意思?由于new此处的 s 不需要初始化/构造相关数据类型,因此它们不会(必然)触发从您隐含计划用于它们的内存中的读取或写入。因此,您可能看不到段错误的一个原因是代码实际上只执行此操作:

char* buffer = new char[100];
float* in_buf = reinterpret_cast<float*>(buffer);

如果您继续读取或写入 ala in_buf[99] = 2;,则更有可能出现段错误,但远不能保证-该地址处的内存可能位于应用程序的虚拟地址空间中。例如,假设对 100 个字符的请求通过对一页内存的请求得到满足,并且操作系统页面大小 >= 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];
于 2012-07-24T02:40:25.263 回答
1

您的第一个问题中的问题可以通过一个很小的变化来说明,除非您并排比较代码,否则您看不到它:

char * buffer = new char[100];
float * in_buf = new(buffer) float[100]();

这给了我一个 MSVS 中的运行时堆损坏错误。

于 2012-07-24T00:59:01.890 回答
0

正如提到的其他答案一样,这条线float * in_buf = new(buffer) float[100];将大部分数组放在buffer. 这不是段错误,因为尚未触及内存。

如果 u 和 v 没有有意义的构造函数(即它们是零初始化的),那么放置 new 没有意义,也不会像这样清晰:

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
};
于 2012-07-24T02:52:34.067 回答