未正确重用内存导致的未定义行为

时间:2014-09-10 05:07:26

标签: c++ constructor

该标准引用以下示例(3.8 / 7 N3797):

struct C 
{
    int i;
    void f();
    const C& operator=( const C& );
};

const C& C::operator=( const C& other) 
{
    if ( this != &other ) 
    {
        this->~C(); // lifetime of *this ends
        new (this) C(other); // new object of type C created
        f(); // well-defined
    }
return *this;
}

C c1;
C c2;
c1 = c2; // well-defined
c1.f(); // well-defined; c1 refers to a new object of type C

如果我们按如下方式实施operator=,是否有UB:

const C& C::operator=( const C& other) 
{
    if ( this != &other ) 
    {                        // Note that there is no more explcicitly destructor call,
                             // since at the time of memory reusing the lifetime of 
                             // this is still going on
        new (this) C(other); // new object of type C created
        f(); // well-defined
    }
return *this;
}

相关引用是:

  

如果的生命周期 已结束在存储之前   对象占用被重用或释放,一个新对象是   在原始对象占用的存储位置创建,a   指向原始对象的指针,引用的引用   到原始对象,或原始对象的名称   自动引用新对象,一旦生命周期   新对象已经启动,可以用来操纵新对象

没有规则:“在存储位置创建新对象而不是对象占用”。 同时,我们对const对象有一个合适的规则。很明显:

第3.8 / 9节:

  

在const对象的存储位置创建新对象   静态,线程或自动存储持续时间占用或,在   这种const对象之前占用的存储位置   终身结束导致未定义的行为。

1 个答案:

答案 0 :(得分:4)

相关规则如下:

  

3.8 / 4 程序可以通过重用对象占用的存储空间来结束任何对象的生命周期   使用非平凡的析构函数显式调用析构函数以获取类类型的对象。对于一个对象   对于具有非平凡析构函数的类类型,程序不需要显式调用析构函数   在重新使用或释放​​对象占用的存储之前;但是,如果没有明确的电话   析构函数或者如果 delete-expression (5.3.5)不用于释放存储,则析构函数不应该是   隐式调用,任何依赖于析构函数产生的副作用的程序都是未定义的   行为。

你的例子,正如所写,是合法的,因为C有一个简单的析构函数。