在头文件<memory>中定义。
std::unique_ptr
是通过指针占有并管理另一对象,并在 unique_ptr
离开作用域时释放该对象的智能指针。
在下列两者之一发生时用关联的删除器释放对象:
(1)销毁了管理的 unique_ptr
对象
struct B {
virtual ~B() = default;
virtual void bar() { std::cout << "B::bar\n"; }
};
struct D : B {
D() { std::cout << "D::D\n"; }
~D() { std::cout << "D::~D\n"; }
void bar() override { std::cout << "D::bar\n"; }
};
int main()
{
auto del = [](D * p) {
std::cout << "deleter called\n";
delete p;
};
std::unique_ptr<D, decltype(del)> p(new D(), del);
//输出:
//D::D
//deleter called
//D::~D
}
(2)通过 operator= 或 reset() 赋值另一指针给管理的 unique_ptr
对象。
使用operator=
:
std::unique_ptr<D> p(new D());
// std::unique_ptr<D> q = p; //错误:不能复制
std::unique_ptr<D> q = std::move(p);
// output:
//D::D
//D::~D
使用reset
:
struct B {
virtual ~B() = default;
virtual void bar() { std::cout << "B::bar\n"; }
};
struct D : B {
D() { std::cout << "D::D\n"; }
D(std::string s) : str(s) { std::cout << "D::D " << s << std::endl; }
~D() { std::cout << "D::~D " << str << std::endl; }
void bar() override { std::cout << "D::bar\n"; }
std::string str = "";
};
int main()
{
auto del = [](D * p) {
std::cout << "deleter called " << p->str << std::endl;;
delete p;
};
std::unique_ptr<D, decltype(del)> p(new D("d1"), del);
p.reset(new D("d2"));
}
输出:
D::D d1
D::D d2
deleter called d1
D::~D d1
deleter called d2
D::~D d2
unique_ptr
亦可以不占有对象,该情况下称它为空 (empty)。
std::unique_ptr
有两个版本:
类满足可移动构造 (MoveConstructible) 和可移动赋值 (MoveAssignable) 的要求,但不满足可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 的要求。
Deleter 必须是函数对象 (FunctionObject) 或到函数对象 (FunctionObject) 的左值引用或到函数的左值引用,可以 unique_ptr<T, Deleter>::pointer 类型参数调用
注解
只有非 const 的 unique_ptr
能转移被管理对象的所有权给另一 unique_ptr
。若对象的生存期为 const std::unique_ptr 所管理,则它被限定在创建指针的作用域中。
std::unique_ptr
常用于管理对象的生存期,包含:
- 正常退出和经由异常退出都可保证删除,提供异常安全,给处理拥有动态生存期的对象的类和函数
- 传递独占的拥有动态生存期的对象的所有权到函数
- 从函数获得独占的拥有动态生存期对象的所有权
- 作为具移动容器的元素类型,例如保有指向动态分配对象的指针的 std::vector (例如,若想要多态行为)
若 T 是某基类 B 的派生类,则 std::unique_ptr<T> 可隐式转换为 std::unique_ptr<B>。产生的 std::unique_ptr<B> 的默认删除器将使用 B 的 operator delete ,这导致未定义行为,除非 B 的析构函数为虚函数。
release
pointer release() noexcept;
若存在,则释放被管理对象的所有权。调用release()后,再调用get() 返回 nullptr 。调用方负责删除该对象。
注意:这里的释放不是销毁对象,只是将其指向的对象释放出去。
返回值:指向被管理对象的指针,或若无被管理对象则为 nullptr ,即调用前 get() 会返回的值。
int main()
{
auto del = [](D * p) {
std::cout << "deleter called " << p->str << std::endl;;
delete p;
};
std::unique_ptr<D, decltype(del)> p(new D("d1"), del);
D *q = p.release();
std::cout << p.get() << std::endl; //输出: 0
std::cout << q->str << std::endl; //输出: d1
delete q;
}
D::D d1
0
d1
D::~D d1
swap
void swap( unique_ptr& other ) noexcept;
交换 *this 和另一个 unique_ptr 对象 other 的托管对象和关联删除器。
int main()
{
std::unique_ptr<D> p(new D("d1"));
std::unique_ptr<D> q(new D("d2"));
p.swap(q);
std::cout << p->str << " " << q->str << std::endl;
}
输出:
D::D d1
D::D d2
d2 d1
D::~D d1
D::~D d2
本文来自博客园,原创作者:Clemens,转载请注明原文链接:https://www.cnblogs.com/errorman/p/17258500.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具