移动 constructor/assignment of std::unique_ptr:内存重新分配?
move constructor/assignment of std::unique_ptr: memory reallocation?
在使用 std::unique_ptr
的移动 constructor/assignment 时,是否可以假设底层对象没有在内存中重新分配,这样指向它的原始指针仍然有效?
考虑以下程序:
#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()} { }
根据标准,[unique.ptr.single.ctor]/20
unique_ptr(unique_ptr&& u) noexcept;
Postconditions: get() yields the value u.get() yielded before the construction. 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; }
在使用 std::unique_ptr
的移动 constructor/assignment 时,是否可以假设底层对象没有在内存中重新分配,这样指向它的原始指针仍然有效?
考虑以下程序:
#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()} { }
根据标准,[unique.ptr.single.ctor]/20
unique_ptr(unique_ptr&& u) noexcept;
Postconditions: get() yields the value u.get() yielded before the construction. 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; }