unique_ptr与函数调用
1、unique_ptr是不可copy,只可以Move
2、在做函数参数或是返回值中一定要注意所有权
函数调用与unique_ptr注意事项
Passing by value 独占指针作为传参的值
· 需要用std::move 来转移内存拥有权,不调用会编译报错
· 如果参数直接传入std:make_unique语句 自动转为move
Passing by reference 传引用作为参数
· 如果设置参数为 const 则不能改变指向,不能够再指向其他的地方
比方说 reset()
reset()方法为智能指针清空方法,指向空
Return by value 作为返回值
· 指向一个 local object
· 可以用作链式函数
代码实践
Passing by value 独占指针作为传参的值
cpp
#include <iostream>
// 智能指针头文件
#include <memory>
// 自定义类头文件
#include "CustomClass.h"
using namespace std;
// 独占指针作为传参的值
void funcPassByValue(std::unique_ptr<CustomClass> c)
{
c->cat_info();
}
int main()
{
std::unique_ptr<CustomClass> upc1 = make_unique<CustomClass>("upc1");
// 1 Pass value
funcPassByValue(std::move(upc1));
std::cout << "----------- END --------------------\n";
return 0;
}
打印结果:

可以看到cat_info被调用,正常打印,但是此时不能再对move后的指针进行操作,会崩溃
尝试对 move 后的指针进行操作
cpp
#include <iostream>
// 智能指针头文件
#include <memory>
// 自定义类头文件
#include "CustomClass.h"
using namespace std;
// 独占指针作为传参的值
void funcPassByValue(std::unique_ptr<CustomClass> c)
{
c->cat_info();
}
int main()
{
std::unique_ptr<CustomClass> upc1 = make_unique<CustomClass>("upc1");
// 1 Pass value
funcPassByValue(std::move(upc1));
// move后再调用原指针,程序会崩溃报错
upc1->cat_info();
std::cout << "----------- END --------------------\n";
return 0;
}
打印结果:


在运行程序后,vs执行发生崩溃。从图中可以看到,代码从 upc1->cat_info 这行语句崩溃,报错为空指针,说明upc1指针已经被转移,原先的指针为空指针了
若直接在参数中进行make,会自动转成move
cpp
#include <iostream>
// 智能指针头文件
#include <memory>
// 自定义类头文件
#include "CustomClass.h"
using namespace std;
// 独占指针作为传参的值
void funcPassByValue(std::unique_ptr<CustomClass> c)
{
c->cat_info();
}
int main()
{
std::unique_ptr<CustomClass> upc1 = make_unique<CustomClass>("upc1");
// 1 Pass value
funcPassByValue(std::move(upc1));
// move后再调用原指针,程序会崩溃报错
// upc1->cat_info();
funcPassByValue(make_unique<CustomClass>()); // 自动转成move
std::cout << "----------- END --------------------\n";
return 0;
}
打印结果:

可以看到 函数中的 cat_info 正常调用,说明 unique_ptr 的所有权被 move 放进了函数中
Passing by reference 传引用作为参数
cpp
#include <iostream>
// 智能指针头文件
#include <memory>
// 自定义类头文件
#include "CustomClass.h"
using namespace std;
// 引用作为参数 不加const
void funcPassByRefNoConst(std::unique_ptr<CustomClass> &c)
{
c->set_name("funcPassByRefNoConst");
c->cat_info();
// 清空指针
c.reset();
}
// 引用作为参数 加const
void funcPassByRefWithConst(const std::unique_ptr<CustomClass> &c)
{
c->set_name("funcPassByRefWithConst");
c->cat_info();
// 清空指针,加const之后就不能再进行reset了
// c.reset();
}
// 返回值为unique_ptr
std::unique_ptr<CustomClass> funcReturnUniquePtr()
{
std::unique_ptr<CustomClass> upc = std::make_unique<CustomClass>("return unique_ptr");
std::cout << "return unique_ptr address:" << upc.get() << std::endl;
std::cout << "return unique_ptr address:" << &upc << std::endl;
return upc;
}
int main()
{
// 2 Pass ref
// 不加const
std::unique_ptr<CustomClass> upc2 = make_unique<CustomClass>("upc2");
funcPassByRefNoConst(upc2);
// 指针被清空,调用会崩溃
// upc2->cat_info();
std::cout << "upc2 address:" << upc2.get() << std::endl;
// 加const
std::unique_ptr<CustomClass> upc3 = make_unique<CustomClass>("upc3");
funcPassByRefWithConst(upc3);
upc3->cat_info();
std::cout << "upc3 address:" << upc3.get() << std::endl;
std::cout << "----------- END --------------------\n";
return 0;
}
打印结果:

通过打印结果得到如下结论
1、可以看到如果指针被 reset 后,指向地址为0,无法再进行get/set 操作。如果不想指针在函数中被修改指向,需要在参数加入 const 修饰,禁止修改指向
2、而且通过打印结果可以看出,Passing by reference 与 Passing by value 是不一样的,Passing by reference 不会修改unique_ptr 的所有权,在函数执行后仍可进行操作
Return by value 作为返回值
cpp
#include <iostream>
// 智能指针头文件
#include <memory>
// 自定义类头文件
#include "CustomClass.h"
using namespace std;
// 返回值为unique_ptr
std::unique_ptr<CustomClass> funcReturnUniquePtr()
{
std::unique_ptr<CustomClass> upc = std::make_unique<CustomClass>("return unique_ptr");
std::cout << "return unique_ptr address:" << upc.get() << std::endl;
std::cout << "return unique_ptr address:" << &upc << std::endl;
return upc;
}
int main()
{
// 3 rerutn
//链式
funcReturnUniquePtr()->cat_info();
std::cout << "----------- END --------------------\n";
return 0;
}
打印结果:
