mardi 21 avril 2020

move constructor/assignment of std::unique_ptr: memory reallocation?

In using move constructor/assignment of std::unique_ptr, can one assume that the underlying object is not reallocated in memory, such that a raw pointer to it remains valid?

Consider the following program:

#include <memory>
#include <utility>
#include <iomanip>
#include <iostream>

template <class T>
struct A {
    std::unique_ptr<T> data = nullptr;
    T *p;
    template <class... U>
    A(U&&... x) : data{std::make_unique<T>(std::forward<U>(x)...)}, p{data.get()} { }
};

int main()
{
    A<int> v{2};
    std::cout << std::hex << v.p << std::endl;
    A<int> w{std::move(v)};
    std::cout << w.p << std::endl;
}

Here w is constructed with the default move constructor of A, which calls the move constructor of std::unique_ptr.

It appears by the output that the underlying allocated int is not really moved in memory, so the default move constructor correctly initialized w.p as identical to v.p. Trying with other types for T gives analog result.

Can one assume that the move constructor of std::unique_ptr does not really move the object in memory, so that in the above program the default move constructor is correct? Is that specified by the language?

Or to avoid a dangling pointer must one add a move constructor explicitly like the following?

A(A<T>&& other) : data{std::move(other.data)}, p{data.get()} { }

Aucun commentaire:

Enregistrer un commentaire