переместить конструктор / назначение std :: unique_ptr: перераспределение памяти? - PullRequest
1 голос
/ 21 апреля 2020

При использовании конструктора перемещения / присваивания std::unique_ptr можно ли предположить, что базовый объект не перераспределен в памяти, так что необработанный указатель на него остается действительным?

Рассмотрим следующую программу:

#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;
}

Здесь w создается с конструктором перемещения по умолчанию A, который вызывает конструктор перемещения std::unique_ptr.

Выходные данные показывают, что базовый выделенный int действительно не перемещен в памяти, поэтому конструктор перемещения по умолчанию правильно инициализировал w.p как идентичный v.p. Попытка с другими типами для T дает аналоговый результат.

Можно ли предположить, что конструктор перемещения std::unique_ptr действительно не перемещает объект в памяти, так что в приведенной выше программе конструктор перемещения по умолчанию является правильным ? Это определяется языком?

Или чтобы избежать висящего указателя, нужно явно добавить конструктор перемещения, как показано ниже:

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

1 Ответ

1 голос
/ 21 апреля 2020

По стандарту, [unique.ptr.single.ctor] / 20

unique_ptr(unique_ptr&& u) noexcept;

Постусловия: get () возвращает значение, полученное u.get () до строительства. u.get () == nullptr.

При построении перемещения не происходит выделения памяти; после A<int> w{std::move(v)};, w.data.get()w.p) будет таким же, как v.data.get() до, то есть v.p.

И конструктор перемещения std::unique_ptr помечается как noexcept, что также подразумевает, что здесь не выделяется память.

IMO, даже неявно сгенерированный конструктор перемещения работает здесь хорошо, лучше добавить пользовательский, особенно если вы можете установить необработанный указатель p на nullptr в перемещенном объекте (для согласованности).

A(A<T>&& other) : data{std::move(other.data)}, p{data.get()} { other.p = nullptr; }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...