运算符new()可以在构造函数运行之前初始化POD吗?

时间:2015-02-01 01:08:19

标签: c++ new-operator undefined-behavior

我认为这个问题可能重复,但我不知道如何搜索它。

我正在尝试重载operator new,这样我可以在课后允许一个可变长度的缓冲区。我当前的设计是否按预期工作,还是未定义的行为?

如果答案在C ++ 98,C ++ 03和C ++ 11中有所不同,请解释其中的差异。

struct POD { /* ...other POD members here... */ };

struct BufferedPOD : POD
{
    size_t n;
    BufferedPOD()
    // Assume n is already initialized...
    {
    }

    static void *operator new(size_t size)
    {
        return ::operator new(size);
    }
    static void *operator new(size_t size, size_t additional_size)
    {
        void *const p = operator new(size + additional_size);
        static_cast<BufferedPOD *>(p)->n = additional_size;
        return p;
    }
    static void operator delete(void *p)
    {
        return ::operator delete(p);
    }
    static void operator delete(void *p, size_t)
    {
        return operator delete(p);
    }
};

int main()
{
    std::auto_ptr<BufferedPOD> p(new (1000) BufferedPOD());
    foo(p.get());  // do something with buffer
    return 0;
}

1 个答案:

答案 0 :(得分:1)

首先,您依赖于未定义的行为,the memory is indeterminate upon calling the constructor

在调试版本中,它通常会填充一些标记图案以便于调试。在版本构建中,这种自由通常只用于加速构造。
在两者中,读取不确定的对象会获得UB,但这将会详细说明。

无论如何,你的方式是错误的(让我们暂时忽略违反“三条法则”的行为:

只需声明::operator new::operator delete的匹配重载,以及工厂函数(应该是唯一可以访问您可用的唯一代码的代码),它使用它并传递额外的 - 空间:

void* operator new(size_t a, size_t b) {
    if(a+b< a || a+b < b)
        throw new std::bad_alloc("::operator new(size_t, size_t) too big");
    return operator new(a+b);
}
void operator delete(void* p, size_t a, size_t b) {return operator delete(p/*, a+b*/);}

struct Buffered : POD { // Not a pod due to inheritance
    Buffered* make(size_t extra) {return new(extra) Buffered(extra);}
private:
    size_t n;
    Buffered(size_t extra) : n(extra) {}
    Buffered(Buffered&) = delete;
    void operator=(Buffered&) = delete;
};