c++智能指针 unique_ptr与函数调用

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;
}

打印结果:

总结

1、unique_ptr 在当作参数传入函数时,只能使用 move 转移所有权,转移所有权后旧指针会被置空

2、unique_ptr 使用引用作为参数时,不需要考虑所有权的问题,但是如果函数中指针指向出现变化(如 reset)可能会导致问题,若不希望指针被修改,需要增加const修饰

3、推荐使用引用传值,使用方便,且问题相对可控

相关推荐
Sakura_j_h_3 小时前
EasyEDA PCB 快速设计Skills
c++·python·github
程序喵大人4 小时前
【C++入门】内存模型与资源管理 - 09 shared_ptr 和 weak_ptr 解决共享,也带来代价
开发语言·c++·资源管理·智能指针·内存模型
jimy16 小时前
C++ 中的 `T&&`:右值引用与转发引用
开发语言·c++
会编程的小孩8 小时前
C++ 定时器
c++
沫璃染墨9 小时前
从零入门计算机网络系列(十一):HTTP协议进阶——从重定向原理到GET/POST与Fiddler抓包
linux·服务器·开发语言·网络·c++·tcp/ip·html
揽星河..11 小时前
【C语言】分支和循环
c语言·c++·算法
Fuyo_111912 小时前
C++ AVL树保姆级详解:从平衡因子到四大旋转机制
java·c++·算法
傲世仙尊13 小时前
继承-类设计层次复用切片转换与菱形继承的死结
c++
架构师伯子明13 小时前
FFmpeg C++学习(一):编译和demo
开发语言·c++·学习
纪念 22914 小时前
C++算法(六)
开发语言·c++·算法