C++智能指针
需要头文件 <memory>
不需要手动释放指针
不是所有指针都能封装成智能指针,很多时候原始指针更加方便。
std::unique_ptr
- 任何时刻都只能有一个指针管理内存
- 当指针超出作用域时自动释放
- 该类型指针不能copy只能move。即转移指针的所有权,记得将原指针置空。使用新new出的类时默认使用move方法。
创建方式:
- 通过裸指针创建(创建后将原始指针置空并销毁,否则不能满足独占的要求)
- 通过new创建
- 通过 std::make_unique 创建(推荐)
通过 get() 获取地址,通过 -> 调用成员函数,通过*解引用
#include <memory>
#include <iostream>
#include <string>
int main()
{
MyClass* p = new MyClass("abc");
std::unique_ptr<MyClass> pp{ p };
std::cout << pp->get_name() << std::endl;
pp->set_name("123");
std::cout << pp->get_name() << std::endl;
std::cout << "--------------- end of main --------------" << std::endl;
}
函数调用传参
- passing by value
使用 std::move 获取内存所有权
如果参数传入 make_unique<>() 语句自动转为 move - passing by reference
如果设置参数为 const 则不能改变指向
比如智能指针清空方法 reset() - return by value
指向一个局部变量
可用作链式函数
#include <memory>
#include <iostream>
#include <string>
void pass_by_value(std::unique_ptr<MyClass> c)
{
std::cout << c->get_name() << std::endl;
std::cout << "------ end of function `pass_by_value` ------" << std::endl;
}
void pass_by_reference(std::unique_ptr<MyClass> &c)
{
c.reset(); // 重置指针,将指针设置为 0
}
void pass_by_const_reference(const std::unique_ptr<MyClass> &c)
{
c->set_name("new name"); // 可以修改对象内部的属性
//c.reset(); 不能使用该方法
}
// 尽量不要使用这种方法
std::unique_ptr<MyClass> get_unique_ptr()
{
// p 对象在函数结束后销毁,p中的原始指针所有权转移到函数调用者手中
std::unique_ptr<MyClass> p = std::make_unique<MyClass>("local unique_ptr");
std::cout << "p.get(): " << p.get() << std::endl; // 01100000 堆上
std::cout << "&p: " << &p << std::endl; // 00EFF5AC 栈上
return p;
}
int main()
{
// 1. pass by value
std::unique_ptr<MyClass> p1 = std::make_unique<MyClass>("MyClass p1");
//pass_by_value(p1); // 这种清空会报错
pass_by_value(std::move(p1)); // 使用move函数后,所有权转到调用函数中,函数结束时销毁对象
p1 = nullptr;
std::cout << std::endl;
// 2. pass by reference (经常用)
std::unique_ptr<MyClass> p2 = std::make_unique<MyClass>("MyClass p2");
pass_by_const_reference(p2);
pass_by_reference(p2);
std::cout << "unique_ptr after reset passed by reference: " << p2.get() << std::endl;
std::cout << std::endl;
// 3. return unique_ptr, chain calls
get_unique_ptr()->get_name();
std::cout << "--------------- end of main --------------" << std::endl;
}
/*
MyClass p1
------ end of function `pass_by_value` ------
Destruct of : MyClass p1
Destruct of : new name
unique_ptr after reset passed by reference: 00000000
p.get(): 007C0318
&p: 006FFC44
Destruct of : local unique_ptr
--------------- end of main --------------
*/
std::shared_ptr
计数指针 共享指针,可以共享数据。
创建了一个计数器与类对象所指内存关联,copy则计数器加一,销毁则计数器减一。api 为use_count()
- pass by value
copy 方式,计数器加一 - pass by reference
const 表示不可以改变智能指针的指向 - return by value(没什么用,尽量返回 unique_ptr)
链式调用
#include <memory>
#include <iostream>
#include <string>
void pass_by_value(std::shared_ptr<MyClass> c)
{
std::cout << "use_count : " << c.use_count() << std::endl;
}
void pass_by_ref(std::shared_ptr<MyClass> &c)
{
std::cout << "address of shared_ptr : " << &c << std::endl;
// 使用 const& 后无法使用 reset
c.reset(new MyClass("new class"));
std::cout << "use_count : " << c.use_count() << std::endl; // 引用传值不会增加计数器的数量
}
int main()
{
// 1. pass by value
std::shared_ptr<MyClass> p = std::make_shared<MyClass>("123");
//函数内 use_count 为 2, 函数外 use_count 为 1
pass_by_value(p);
std::cout << "use count in main function : " << p.use_count() << std::endl;
std::cout << std::endl;
// 2. pass by reference
std::cout << "address of shared_ptr : " << &p << std::endl;
std::cout << "MyClass's address before reset : " << p.get() << std::endl;
pass_by_ref(p);
std::cout << "MyClass's address after reset : " << p.get() << std::endl;
std::cout << "name of p after reset : " << p->get_name() << std::endl;
std::cout << std::endl;
std::cout << "--------------- end of main --------------" << std::endl;
return 0;
}
/*
use_count : 2
use count in main function : 1
address of shared_ptr : 00AFFD78
MyClass's address before reset : 00E3679C
address of shared_ptr : 00AFFD78
Destruct of : 123
use_count : 1
MyClass's address after reset : 00E41280
name of p after reset : new class
--------------- end of main --------------
Destruct of : new class
*/
unique_ptr 和 shared_ptr
unique_ptr 可以转为 shared_ptr(通过 std::move()),但是 shared_ptr 不能转为 unique_ptr
返回值尽量使用 unique_ptr 指针
#include <memory>
#include <iostream>
#include <string>
std::unique_ptr<MyClass> get_unique_ptr()
{
return std::make_unique<MyClass>("new MyClass");
}
int main()
{
std::unique_ptr<MyClass> p1 = std::make_unique<MyClass>("123");
std::shared_ptr<MyClass> p2 = std::move(p1); // p1内部的对象已经转移到了p2中
std::cout << "use_count of p2 : " << p2.use_count() << std::endl;
std::cout << "address of p1.get() : " << p1.get() << std::endl;
//p1->get_name(); // 此语句报错
std::unique_ptr<MyClass> p3 = get_unique_ptr();
std::shared_ptr<MyClass> p4 = get_unique_ptr();
std::cout << "p3'name : " << p3->get_name() << std::endl;
std::cout << "p4'name : " << p4->get_name() << std::endl;
std::cout << "--------------- end of main --------------" << std::endl;
return 0;
}
/*
use_count of p2 : 1
address of p1.get() : 00000000
p3'name : new MyClass
p4'name : new MyClass
--------------- end of main --------------
Destruct of : new MyClass
Destruct of : new MyClass
Destruct of : 123
*/
std::weak_ptr
不拥有所有权,不能调用 -> 和 *
使用场景:A类中需要存储其他A类型对象的信息,如果使用 shared_ptr 就会出现循环依赖问题.所以这里使用没有所有权的指针标记该对象
class MyClass
{
public:
MyClass() = default;
MyClass(const std::string);
~MyClass();
std::string get_name() const;
void set_name(const std::string);
void set_friend(const std::shared_ptr<MyClass>);
private:
std::string name;
std::weak_ptr<MyClass> myFriend; // 此处如果使用 shared_ptr 在函数结束自动销毁时可能无法正常销毁关联类,从而造成内存泄露
};
可以使用 lock() 函数升级成 shared_ptr 类型指针
#include <memory>
#include <iostream>
#include <string>
int main()
{
std::shared_ptr<MyClass> p1 = std::make_shared<MyClass>("123");
std::weak_ptr<MyClass> p2{ p1 };
std::cout << "p1'use_count : " << p1.use_count() << std::endl;
std::cout << "p2'use_count : " << p2.use_count() << std::endl;
std::cout << std::endl;
std::shared_ptr<MyClass> p3 = p2.lock();
std::cout << "p1'use_count : " << p1.use_count() << std::endl;
std::cout << "p2'use_count : " << p2.use_count() << std::endl;
std::cout << "p3'use_count : " << p3.use_count() << std::endl;
std::cout << "--------------- end of main --------------" << std::endl;
return 0;
}
标签:std,include,cout,C++,智能,unique,ptr,指针
From: https://www.cnblogs.com/zhh567/p/16745671.html