在使用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
的move构造函数构造的,该构造函数调用std::unique_ptr
的move构造函数。
从输出看来,底层分配的int
并没有真正在内存中移动,因此默认的move构造函数正确地初始化了w.p
与v.p
相同。
为T
尝试其他类型会产生模拟结果。
可以假设std::unique_ptr
的move构造函数并未真正在内存中移动对象,因此在上述程序中,默认的move构造函数正确吗?
是语言指定的吗?
还是要避免悬空的指针,必须像下面这样显式地添加一个move构造函数?
A(A<T>&& other) : data{std::move(other.data)}, p{data.get()} { }
答案 0 :(得分:1)
根据标准[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
的move构造函数被标记为noexcept
,这也意味着此处没有内存分配。
IMO甚至隐式生成的move构造函数在这里都可以正常工作,添加一个用户定义的更好,尤其是可以在已移动对象中将原始指针p
设置为nullptr
(出于一致性)
A(A<T>&& other) : data{std::move(other.data)}, p{data.get()} { other.p = nullptr; }