5

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.

Bogdan Ionitza
  • 331
  • 1
  • 6
  • 14
  • Placement or other `new` obtains memory. Constructor turns memory into an object. `new` doesn't care what you do with the memory. Constructor doesn't care how you obtain the memory. Yes the behavior is undefuned but it has nothing to do with the way you allocate the offending object. Could be automatic or any other kind. – n. m. could be an AI Jul 03 '16 at 16:34

1 Answers1

7

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.

tkausl
  • 13,686
  • 2
  • 33
  • 50