Search code examples
c++c++11placement-newmove-constructor

move-construct object with placement new


Is it not UB to move-construct an object via placement new?

Let's say I have this code:

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
}

If it's not obvious, f1's member foo_ will have an undefined value after constructing the second foo by placement new and move construction (this undefined value comes from the uninitialized Foo f2's foo_ inside its move-constructor because the values are swapped)

Thus, when exiting the scope of bar(), f1's destructor will try to delete an invalid (uninitialized) pointer.


Solution

  • This has nothing to do with placement new. This code would have the exact same problem:

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

    Every constructed object will get destructed eventually, so it doesn't matter if you use placement-new or not, your move-constructor messes up by leaving the moved-from object in a invalid state. Moving from an object doesn't mean it won't get destructed. It will. You have to let a valid object behind when you move from it.

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

    will fix the bug.