Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 462
Bogdan Ionitza Avatar asked Mar 12 '23 19:03

Bogdan Ionitza


1 Answers

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.

like image 85
tkausl Avatar answered Mar 19 '23 18:03

tkausl