使用 new 放置移动构造对象

move-construct object with placement new

通过placement new移动构造对象不是UB吗?

假设我有这个代码:

class Foo {
public:
    Foo() { foo_ = new int; }
    ~Foo() { delete foo_; }
    Foo(Foo &&f) {
        foo_ = std::swap(f.foo_, foo_);
    }
private:
    int* foo_;
}

void bar() {
    void* pMem = malloc(sizeof(Foo));
    Foo f1;
    // move-construct with placement new:
    new((Foo*)pMem) Foo(std::move(f1)); // f2 in *pMem

    // now f1 will contain a pointer foo_ of undefined value
    // when exiting scope f1.~Foo(){} will exhibit UB trying to delete it
}

如果不是很明显,f1 的成员 foo_ 在通过放置 new 和移动构造构造第二个 foo 后将具有未定义的值(此未定义的值来自未初始化的 Foo f2 的 foo_ 在其移动构造函数中,因为值是 交换)

因此,当退出 bar() 的作用域时,f1 的析构函数将尝试删除无效(未初始化)的指针。

这与展示位置无关。此代码会有完全相同的问题:

void bar() {
    Foo f1;
    Foo f2(std::move(f1));
}

每个构造的对象最终都会被破坏,所以不管你是否使用新的放置,你的移动构造函数都会因为离开移动的而变得混乱处于无效状态的对象。从对象移动并不意味着它不会被破坏。它会。当你离开它时,你必须让一个有效的物体在后面。

Foo(Foo &&f) : foo_(nullptr) {
    std::swap(f.foo_, foo_);
}

将修复错误。