首页 > 编程语言 >c++中unique_ptr 的使用和理解

c++中unique_ptr 的使用和理解

时间:2023-08-07 11:46:39浏览次数:52  
标签:std unique cout demo c++ include ptr

unique_ptr 的使用

std::unique_ptr是c++11起引入的智能指针,为什么必须要在c++11起才有该特性,主要还是c++11增加了move语义,否则无法对对象的所有权进行传递。

unique_ptr 介绍

  • unique_ptr 不共享它的指针。它无法复制到其他 unique_ptr,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL) 算法。只能移动unique_ptr。这意味着,内存资源所有权将转移到另一 unique_ptr,并且原始 unique_ptr 不再拥有此资源。建议将对象限制为由一个所有者所有,因为多个所有权会使程序逻辑变得复杂。因此,当需要智能指针用于纯 C++ 对象时,可使unique_ptr,而当构造 unique_ptr 时,可使用make_unique 函数。make_unique函数是从C++14之后才有。
  • std::unique_ptr 实现了独享所有权的语义。一个非空的 std::unique_ptr 总是拥有它所指向的资源。转移一个 std::unique_ptr 将会把所有权也从源指针转移给目标指针(源指针被置空)。拷贝一个 std::unique_ptr 将不被允许,因为如果你拷贝一个 std::unique_ptr ,那么拷贝结束后,这两个 std::unique_ptr 都会指向相同的资源,它们都认为自己拥有这块资源(所以都会企图释放)。因此 std::unique_ptr 是一个仅能移动(move_only)的类型。当指针析构时,它所拥有的资源也被销毁。默认情况下,资源的析构是伴随着调用 std::unique_ptr 内部的原始指针的 delete 操作的。

示例程序

  • 示例程序1
#include <memory>
#include <iostream>
#include <utility>

class Foo{

public:
    Foo() = default;
    Foo(int a):_a(a) {}
    ~Foo() {}
    int get_a(){
        return _a;
    }
    void set_a(int a) {
        _a = a;
    }
private:
    int _a;

};

std::unique_ptr<Foo> change_a(std::unique_ptr<Foo> f)
{
    f->set_a(10);
    return f;
}

int main()
{
    // std::make_unique是c++14才有
    std::unique_ptr<Foo> pf = std::make_unique<Foo>(10);
    // unique_ptr的复制构造函数和拷贝构造函数是删除了的,这样保证了对象独占,如果不是独占,那么跟shared_ptr
    // 就是一样的功能了。
    // std::unique_ptr<Foo> pf1 = pf;  // compile error

    // 按值传参,会有拷贝问题,同上
    // auto p = change_a(pf);   //compile error

    auto p = change_a(std::move(pf));
    std::cout << "get_a = " << p->get_a() << std::endl;
    if(!pf)
    {
        std::cout << "pf is nullptr" << std::endl;
    }
    //owner transfer from function
    std::unique_ptr<Foo> pf2 = std::make_unique<Foo>(11);
    std::unique_ptr<Foo> p2 = change_a(std::move(pf2));
    std::cout << "get_a = " << p2->get_a() << std::endl;
    if(!pf2)
    {
        std::cout << "pf2 is nullptr" << std::endl;
    }

    //使用reset
    pf2.reset(new Foo(12));
    std::cout << "pf2 is not null: " << pf2->get_a() <<  std::endl;

    //release获取原始指针
    Foo* ff = pf2.release();
    if(!pf2)
    {
        std::cout << "pf2 is nullptr" << std::endl;
    }
    std::cout << "ff is not null: " << ff->get_a() <<  std::endl;

    return 0;
}

输出结果

get_a = 10
pf is nullptr
get_a = 10
pf2 is nullptr
pf2 is not null: 12
pf2 is nullptr
ff is not null: 12
  • 示例程序2
#include <cassert>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <locale>
#include <memory>
#include <stdexcept>

// helper class for runtime polymorphism demo below
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"; }
};

// a function consuming a unique_ptr can take it by value or by rvalue reference
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
  p->bar();
  return p;
}

// helper function for the custom deleter demo below
void close_file(std::FILE* fp)
{
  std::fclose(fp);
}

// unique_ptr-based linked list demo
struct List
{
  struct Node
  {
    int data;
    std::unique_ptr<Node> next;
  };

  std::unique_ptr<Node> head;

  ~List()
  {
    // destroy list nodes sequentially in a loop, the default destructor
    // would have invoked its `next`'s destructor recursively, which would
    // cause stack overflow for sufficiently large lists.
    while (head)
    {
      auto next = std::move(head->next);
      head = std::move(next);
    }
  }

  void push(int data)
  {
    head = std::unique_ptr<Node>(new Node{data, std::move(head)});
  }
};

int main()
{
  std::cout << "1) Unique ownership semantics demo\n";
  {
    // Create a (uniquely owned) resource
    std::unique_ptr<D> p = std::make_unique<D>();

    // Transfer ownership to `pass_through`,
    // which in turn transfers ownership back through the return value
    std::unique_ptr<D> q = pass_through(std::move(p));

    // p is now in a moved-from 'empty' state, equal to nullptr
    assert(!p);
  }

  std::cout << "\n" "2) Runtime polymorphism demo\n";
  {
    // Create a derived resource and point to it via base type
    std::unique_ptr<B> p = std::make_unique<D>();

    // Dynamic dispatch works as expected
    p->bar();
  }

  std::cout << "\n" "3) Custom deleter demo\n";
  std::ofstream("demo.txt") << 'x'; // prepare the file to read
  {
    using unique_file_t = std::unique_ptr<std::FILE, decltype(&close_file)>;
    unique_file_t fp(std::fopen("demo.txt", "r"), &close_file);
    if (fp)
      std::cout << char(std::fgetc(fp.get())) << '\n';
  } // `close_file()` called here (if `fp` is not null)

  std::cout << "\n" "4) Custom lambda-expression deleter and exception safety demo\n";
  try
  {
    std::unique_ptr<D, void(*)(D*)> p(new D, [](D* ptr)
                                        {
                                          std::cout << "destroying from a custom deleter...\n";
                                          delete ptr;
                                        });

    throw std::runtime_error(""); // `p` would leak here if it were a plain pointer
  }
  catch (const std::exception&) { std::cout << "Caught exception\n"; }

  std::cout << "\n" "5) Array form of unique_ptr demo\n";
  {
    std::unique_ptr<D[]> p(new D[3]);
  } // `D::~D()` is called 3 times

  std::cout << "\n" "6) Linked list demo\n";
  {
    List wall;
    const int enough{1'000'000};
    for (int beer = 0; beer != enough; ++beer)
      wall.push(beer);

    std::cout.imbue(std::locale("en_US.UTF-8"));
    std::cout << enough << " bottles of beer on the wall...\n";
  } // destroys all the beers
}

输出

1) Unique ownership semantics demo
D::D
D::bar
D::~D

2) Runtime polymorphism demo
D::D
D::bar
D::~D

3) Custom deleter demo
x

4) Custom lambda-expression deleter and exception safety demo
D::D
destroying from a custom deleter...
D::~D
Caught exception

5) Array form of unique_ptr demo
D::D
D::D
D::D
D::~D
D::~D
D::~D

6) Linked list demo
1,000,000 bottles of beer on the wall...

标签:std,unique,cout,demo,c++,include,ptr
From: https://www.cnblogs.com/weihao-ysgs/p/unique_ptr.html

相关文章

  • 【开源三方库】Aki:一行代码极简体验JS&C++跨语言交互
     开源项目 OpenHarmony是每个人的 OpenHarmony 一、简介OpenAtom OpenHarmony(以下简称“OpenHarmony”)的前端开发语言是ArkTS,在TypeScript(简称TS)生态基础上做了进一步扩展,继承了TS的所有特性,是JavaScript(简称JS)的超集。而Node-API(简称NAPI)是方舟引擎用于封装JS能力为......
  • c++中的weak_ptr的使用与理解
    weak_ptr的使用\(\quad\)关于为什么使用weak_ptr,以及他的使用场景,我们在这篇文章中已经进行了介绍。而对于其具体的使用方法,比如说如何通过weak_ptr访问内存中的数据等操作还未提及,这里做个简单赘述。\(\quad\)有一句话说的很好:weak_ptr就像观测者那样观测资源的使用情况......
  • C++实现高精度减法
    一、问题描述:    高精度算法是处理大数字的数学计算方法。在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字。一般这类数字我们统称为高精度数,高精度算法是用计算机对于超大数据的一种模拟加,减,乘,除,乘方,阶乘,开方等运算。对于非常庞大......
  • 配置 Sublime Text4为 C++ 编辑器的方法
    概述涉及以下插件的安装和配置PackageControl Terminus LSP LSP-clangd clang-format LSP-pyright LSP-json配置sublime安装PackageControl以进行包管理。Terminus安装Terminus以实现sublimetext4内的terminal。绑定快捷键:[ { "keys":[ "ctrl+shift+t" ], "com......
  • msvc++工程之vs版本升级及工程目录规范
    为什么要升级msvc++工程版本对msvc++工程进行vs版本升级,一方面是可以使用较新的C++标准及对64位更好的支持。首先你需要对msvc++project文件有一定的了解,主要是vcxproj和vcxproj.filter这两个文件,升级的时候需要手动修改sln和vcxproj文件。vs(visualstuiod)中vc++工程的Filte......
  • C++核心编程——引用
    引用1引用的基本使用作用:给变量起别名语法:数据类型&别名=原名示例:intmain(){ inta=10; int&b=a; cout<<"a="<<a<<endl; cout<<"b="<<b<<endl; b=100; cout<<"a="&......
  • C与C++之间的相互调用及函数区别
    最近项目需要使用googletest(以下简称为gtest)作为单元测试框架,但是项目本身过于庞大,main函数无从找起,需要将gtest框架编译成静态库使用。因为项目本身是通过纯c语言编写,而gtest则是一个c++编写的测试框架,其中必然涉及c与c++之间的相互调用。注意,本文的前提是,c代码采用gcc等c语言编......
  • C/C++经典书籍
    记录四本C/C++的经典书籍。最经典的莫过于1988年出版的《TheCProgrammingLanguage》第二版1.C1.1零基础:CPrimerPlus,SixthEdition,作者:StephenPrata,2013年出版,涵盖C11标准1.2C语言作者巨著(适合有C基础的阅读):TheCProgrammingLanguage,SecondEdition,作者:Denni......
  • C++入门到放弃(09)——友元:friend
    ​1.基本用法友元的概念还是比较简单的,主要作用是,让声明的友元函数或者友元类,可以直接访问当前类的私有成员。可以这样理解,友元声明代表了,向大家说明这个函数或类是我的朋友(friend),因此它可以随意使用我内部的私有成员。基本形式:friend+函数声明friend+class+类名classPoin......
  • 【VSCode】mac系统利用VSCode配置C++环境
    https://blog.csdn.net/bsy1111/article/details/131056647在官网上看到VSformac不能建C++项目,找到一个教程用VSCode配置一下C++环境可以跑点简单的代码应付一下日常使用,要是有大佬知道怎么在mac上用VisualStudio写C++的话还麻烦不吝赐教......