该标准引用以下示例(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
Run Code Online (Sandbox Code Playgroud)
如果我们实现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;
}
Run Code Online (Sandbox Code Playgroud)
相关报价为:
如果在对象的生命周期结束后,在 对象所占用的存储空间被重用或释放之前,在原对象所占用的存储位置创建一个新对象,一个指向原对象的指针,一个引用引用原始对象,或者原始对象的名称将自动引用新对象,并且一旦新对象的生命周期开始,就可以用于操作新对象
没有以下规则:“在对象占用的存储位置创建一个新对象”。同时,我们有一个适合const对象的规则。很明显:
第 3.8/9 节:
在创建存储位置是一个const对象的新对象与静态,螺纹,或自动存储时间占用或者,那个曾经占领其生命周期结束导致不确定的行为之前,这样的const对象的存储位置。
相关规则是这样的:
3.8/4程序可以通过重用对象占用的存储空间或通过显式调用具有非平凡析构函数的类类型对象的析构函数来结束任何对象的生命周期。对于具有非平凡析构函数的类类型的对象,程序不需要在对象占用的存储空间被重用或释放之前显式调用析构函数;但是,如果没有显式调用析构函数或者如果没有使用删除表达式(5.3.5)来释放存储,则不应隐式调用析构函数以及任何依赖于析构函数产生的副作用的程序有未定义的行为。
你写的例子是合法的,因为C有一个微不足道的析构函数。