能否将std::unique_ptr<T>指向的对象移入std::vector<T>且无额外副本?
问题描述
假设我有一个存储泛型T对象的vector:
std::vector<T> vector_of_ts = {...};
该vector本质上是底层堆分配的T对象数组。现在我有以下代码:
std::unique_ptr<T> t = std::make_unique<T>(...);
这同样是底层堆分配的T对象。是否可以通过移动操作将该对象推入vector,而不产生临时或额外副本?类似如下操作:
vector_of_ts.move(*t)
解决方案
当然可以实现无额外副本的转移,但你写的vector_of_ts.move(*t)不是标准用法,正确的做法分两种情况:
情况1:将unique_ptr指向的对象移动到vector
如果你想把unique_ptr管理的T对象移动到vector里,不需要额外拷贝,只需对*t执行移动构造,再手动置空unique_ptr避免重复释放:
vector_of_ts.emplace_back(std::move(*t)); t.reset(); // 必须手动置空,否则unique_ptr析构时会释放已转移到vector的对象
这里std::move(*t)会把*t转换成右值,触发T的移动构造函数(前提是T支持移动语义),vector会直接在自身堆内存中构造对象,无额外拷贝。
情况2:将unique_ptr本身存入vector
如果需要让vector存储unique_ptr<T>而非T对象,直接移动unique_ptr即可,这一操作仅转移指针所有权,完全无对象拷贝:
std::vector<std::unique_ptr<T>> vec_of_ptrs; vec_of_ptrs.push_back(std::move(t));
注意事项
- 第一种情况中必须调用
t.reset(),否则unique_ptr仍持有原对象指针,生命周期结束时会尝试释放已属于vector的对象,引发双重释放错误。 - 若
T不支持移动语义(比如未定义移动构造函数且编译器无法生成默认版本),移动操作会退化为拷贝,此时无法避免拷贝行为。
内容的提问来源于stack exchange,提问作者Ignorant
相关产品推荐
相关产品推荐

