移动构造位置为new的对象

move-construct object with placement new

本文关键字:new 对象 位置 移动      更新时间:2023-10-16

是不是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
}

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

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

这与位置new无关。这段代码会有完全相同的问题:

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

每个构造的对象最终都会被析构,所以不管你是否使用place -new,你的move-构造函数都会因为让move- from对象处于无效状态而出错。从一个对象移动并不意味着它不会被破坏。它将。当你离开一个有效的对象时,你必须让它留在后面。

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