C++ unique_ptr简单使用

发布时间 2023-12-22 16:51:32作者: 蔡头一枚

#######################智能指针(智能指针是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保在离开指针所在作用域时,自动正确的销毁动态分配的对象,防止内存泄漏)
头文件#include <memory>
unique_ptr特性 (属性为对象, 而不是指针, 管理指针)
(1).基于排他所有权模式:两个指针不能指向同一个资源
无法进行左值unique_ptr复制构造,也无法进行左值复制赋值操作,但允许临时右值赋值构造和赋值
保存指向某个对象的指针,当它本身离开作用域时会自动释放它指向的对象。
在容器中保存指针是安全的
无法进行左值复制赋值操作,但允许临时右值赋值构造和赋值, 结合std::move()使用, 将一个

(2). unique_ptr做为STL容器的元素时,不能作为类的成员变量; share_ptr可以作为类成员嵌套使用
例如:

class b{
private:
vector<unique_ptr<int>> temp; //错误
vector<unique_ptr<a>> tmp; //错误
}

(3). unique_ptr做为STL容器的元素时,不能直接进行传递,因为不可以进行拷贝和赋值操作.
vector<unique_ptr<int>> a;
a.push_back(new int(20)); //错误
a.emplace_back(new int(20)); //错误
a.emplace_back(make_unique<int>(20)); //错误

 


方法:
1. get(); // 返回对象管理的裸指针,带有风险性
2. release(); // 释放,调用后智能指针和其所指向对象的联系再无联系,但是该内存仍然存在有效。它会返回裸指针,但是该智能指针被置空。
返回的裸指针我们可以手工delete来释放,也可以用来初始化另外一个智能指针,或者给另外一个智能指针赋值。
3. reset();
reset()不带参数情况:释放智能指针所指向的对象(释放因为它是独占,而不像shared_ptr还需要考虑引用计数),并将智能指针置空。
reset()带参数时:释放智能指针所指向的对象,并将该智能指针指向新对象。

4. swap(); // 交换智能指针


例如:
unique_ptr<string> pointer(new string("123456"));
unique_ptr<string> pointer2(new string("888888"));

pointer = pointer2; // 非法, 禁止左值赋值操作
unique_ptr<string> pointer3(pointer2); // 禁止左值赋值构造

unique_ptr<string> p3(std::move(p1)); // 合法, std::move()将左值改变成右值
p1 = std::move(p2); // 使用move把左值转成右值就可以赋值了,效果和auto_ptr赋值一样

简单代码例子:

#include <iostream>
#include <string>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <vector>

using namespace std;

class Absobj
{
public:
    Absobj()
    {
        printf("Create Abs - address: %p\n", this);
    }

    void print()
    {
        printf("Absobj print------\n");
    }

    ~Absobj()
    {
        printf("~Del AbsObj - address: %p\n", this);
    }

    char *pBuf = nullptr;
    int m_num = 0;
};


unique_ptr<Absobj> createPoint(int num)
{
    unique_ptr<Absobj> ptr(new Absobj);
    printf("ptr: %p\n", &ptr);
    ptr->m_num = num;
    return ptr;
}

void dowork(std::unique_ptr<Absobj> &&ptr)
{
    printf("ptr: %d\n", ptr->m_num);
    ptr->m_num = 888;
}

void gowork(std::unique_ptr<Absobj> ptr)
{
    printf("-->ptr: %d\n", ptr->m_num);
}

void towork(std::unique_ptr<Absobj> &ptr)
{
    printf(">>>ptr: %d\n", ptr->m_num);
}

int main(void)
{
    vector<unique_ptr<Absobj>> vec;

    unique_ptr<Absobj> ptr(new Absobj);
    ptr->m_num = 123;
    printf("ptr address: %p | num: %d\n", &ptr, ptr->m_num);

    dowork(std::move(ptr));         // 二级引用做参数,操作的是本身,std::move不会释放智能指针对象
    if ( ptr == nullptr )
    {
        printf("Ptr is Null.\n");
    }

    towork(ptr);                    // 引用传递,智能指针直接做为参数,可不用作为右值传递,
    if ( ptr == nullptr )
    {
        printf("===Ptr is Null.\n");
    }

    gowork(std::move(ptr));         // 值传递, 不能直接传递左值(unique_ptr不支持拷贝赋值),只能转换成右值传递
    if ( ptr == nullptr )
    {
        printf(">>>Ptr is Null.\n");
    }    
     return 0;    
}

程序运行情况: