深入学习C++智能指针之shared_ptr与右值引用的方法

深入学习C++智能指针之shared_ptr与右值引用的方法

本文将介绍C++中的智能指针shared_ptr和右值引用的概念及其用法,其中注意点将在示例中一并说明。

shared_ptr

shared_ptr是C++11中的智能指针,用于管理动态分配内存的生命周期。shared_ptr采用引用计数的机制,每个shared_ptr都能访问同一块内存,当最后一个指向该内存的shared_ptr被销毁时,内存就会被释放。使用shared_ptr能够有效地避免内存泄漏。

shared_ptr的创建

shared_ptr的创建可以通过直接赋值或者make_shared函数来实现。

直接赋值方式

//示例1:
//普通指针的创建
int *p = new int(10);
//shared_ptr的创建
shared_ptr<int> sp(p);

shared_ptr<int>用于指定shared_ptr的类型,sp是shared_ptr的对象名,p是普通指针的名称。当sp析构时,它会自动释放p所指向的内存。

make_shared函数

make_shared函数能够更加方便地创建shared_ptr。

//示例2:
auto sp1 = make_shared<int>(10); //等同于shared_ptr<int> sp(new int(10))
auto sp2 = make_shared<string>("hello"); //等同于shared_ptr<string> sp(new string("hello"))

make_shared函数可以更加简明地创建shared_ptr,类型名和内存分配都通过参数确定。

shared_ptr的使用

shared_ptr的使用方法和常规指针类似,可以通过解引用符号*和箭头符号->来访问存储在shared_ptr中的对象。

//示例3:
auto sp1 = make_shared<int>(10);
auto sp2 = sp1;
cout << *sp1 << " " << *sp2 << endl; //输出:10 10
*sp1 = 20;
cout << *sp1 << " " << *sp2 << endl; //输出:20 20

示例中,sp2也指向了sp1所指向的内存,所以*sp1*sp2的值相同,当对*sp1赋值后,两个指针所指向的值均发生了变化。

shared_ptr的注意点

在使用shared_ptr的过程中,需要注意以下几点。

避免循环引用

循环引用是指两个或者多个对象之间相互引用,这种情况常常会导致内存泄漏。使用shared_ptr的时候,尤其要注意避免循环引用造成的问题。

//示例4:
struct B;
struct A
{
  shared_ptr<B> m_Bptr;
  ~A() {cout << "A deleted" << endl;}
};

struct B
{
  shared_ptr<A> m_Aptr;
  ~B() {cout << "B deleted" << endl;}
};

void Test()
{
  shared_ptr<A> a(new A);
  shared_ptr<B> b(new B);
  a->m_Bptr = b; //A实例持有B实例的shared_ptr 
  b->m_Aptr = a; //B实例持有A实例的shared_ptr
}

在示例4中,A类和B类相互持有对方的shared_ptr,在函数结束时,由于相互持有,导致shared_ptr引用计数不为0,出现内存泄漏的问题。这种情况可以通过使用weak_ptr等方式来避免。

非空判断

在使用shared_ptr的时候,需要对其进行非空判断,以避免使用空指针造成程序崩溃的问题。

//示例5:
void Test(shared_ptr<int> sp)
{
  if(sp) //对shared_ptr进行非空判断
  {
    cout << *sp << endl;
  }
}

int main()
{
  shared_ptr<int> sp;
  Test(sp);
  return 0;
}

在示例5中,如果sp为null,则直接忽略某些逻辑,以避免空指针的使用。

右值引用

右值引用是与左值引用对应的概念,右值指的是表达式传递给函数的临时变量或者和常量,通过右值引用,可以将右值直接绑定到函数中,从而避免复制和引用操作。

右值引用的创建

右值引用使用语法为:类型名&& 变量名

//示例6:
void Func(int&& value)
{
  cout << value << endl;
}

int main()
{
  int a = 10;
  Func(a + 3); //将表达式a+3作为右值直接传递给函数Func
  return 0;
}

在示例6中,a + 3是一个临时变量,通过右值引用,可以将其直接传递给函数Func,以避免复制。在函数中,需要使用std::move来转移右值引用,避免出现悬垂指针的问题。

右值引用的注意点

在使用右值引用时,需要注意以下几点。

不能返回局部变量的引用

右值引用不能返回指向局部变量的指针或者引用,因为局部变量的生命周期与函数调用结束时一致。

//示例7:
int&& Func()
{
  int value = 10;
  return std::move(value); //error: 对 'value' 做右值引用不能将 'value' 作为 'int&&' 的初始值
}

int main()
{
  int&& a = Func();
  cout << a << endl;
  return 0;
}

在示例7中,Func函数返回一个指向局部变量value的右值引用,在返回时value已被销毁,导致悬垂指针的问题。

左值和右值的区别

在使用右值引用时,需要正确地区分左值和右值,以免出现不必要的问题。

//示例8:
void Func(int& value) //对左值参考
{
  cout << "左值" << endl;
}

void Func(int&& value) //对右值引用
{
  cout << "右值" << endl;
}

int main()
{
  int a = 10;
  Func(a); //输出“左值”
  Func(10); //输出“右值”
  return 0;
}

在示例8中,对左值的引用和对右值的引用都是合法的,需要根据实际情况选择正确的引用方式。

总结

本文介绍了C++11中的智能指针shared_ptr和右值引用,包括它们的创建和使用方法,以及需要注意的细节。通过学习本文,可以更加清晰地理解这些概念,并能够灵活应用到实际编程中。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入学习C++智能指针之shared_ptr与右值引用的方法 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • javascript数据类型示例分享

    JavaScript数据类型示例分享 在JavaScript中,共有6种原始数据类型和1种引用类型。以下是每种数据类型的示例及其说明。 1. 原始数据类型 1.1 数字类型(Number) JavaScript中的数字类型是一个非常常用的数据类型,表示数字,它可以是整型或浮点数。 示例1: let num1 = 100; // 整型 let num2 = 3…

    other 2023年6月27日
    00
  • 关于python:以全精度打印numpy.float64

    在Python中,使用numpy.float64类型的变量时,有时需要以全精度打印它们的值。以下是以全精度打印numpy.float64的完整攻略: 导入numpy模块 在使用numpy.float64之前,需要先导入numpy模块。可以使用以下命令导入numpy模块: import numpy as np 设置打印选项 在打印numpy.float64变量…

    other 2023年5月8日
    00
  • Android安卓5.0系统正式版刷机包(镜像)官方下载地址汇总(适配设备)

    Android安卓5.0系统正式版刷机包(镜像)官方下载地址汇总(适配设备)攻略 1. 准备工作 在开始刷机之前,确保你已经完成以下准备工作:- 一台适配Android 5.0系统的设备(例如:手机、平板等)- 电脑,并确保已经安装了ADB工具和相应的驱动程序- USB数据线- 备份你的设备数据,因为刷机会清除所有数据 2. 下载刷机包 在这里,我们提供了A…

    other 2023年8月4日
    00
  • vue的重点8:slice()、splice()、split()、join()详解

    在Vue中,slice()、splice()、split()、join()是常用的数组和字符串方法。下面是这些方法的详细攻略: slice() slice()方法用于从数组中提取指定的元素。它不会修改原始数组,而是返回一个新的数组,包含从开始到结束(不包括结束)的元素。下面是一个示例: const fruits = [‘apple’, ‘banana’, ‘…

    other 2023年5月8日
    00
  • RSync文件备份同步 Linux服务器rsync同步配置图文教程

    我来详细讲解一下“RSync文件备份同步 Linux服务器rsync同步配置图文教程”。 什么是RSync? RSync是一个在类Unix系统中,用于同步文件和目录的实用工具。RSync通过使用Rsync算法(一种数据压缩算法)注重快速和最小化传输文件,并且允许选择性的更新文件。其他常见的使用情况就是用作备份服务来使用,除此之外,它还是一个优秀的网站、文件镜…

    other 2023年6月27日
    00
  • Microsoft VBScript 编译器错误 错误原因 代码大全

    Microsoft VBScript 编译器错误指的是使用VBScript语言编写的代码在编译运行过程中出现的异常情况。以下是错误原因和代码大全: 错误原因 1.语法错误:VBScript脚本语言非常严格,语法错误包括变量拼写错误、语句缺失、不完整的括号等。 2.类型不匹配:VBScript是一种弱类型语言,这意味着如果变量的值和使用的对象类型不一致,会导致…

    other 2023年6月26日
    00
  • 基于iScroll实现内容滚动效果

    下面是“基于iScroll实现内容滚动效果”的完整攻略: 简介 iScroll是一个高性能的,跨平台的 JavaScript 插件,能够实现 DOM 元素在移动端的各种滚动效果,包括纵向的、横向的滚动效果、卡片式滚动等多种滚动方式。通过 iScroll 可以帮助我们快速构建出移动端的轻量级滚动组件。 安装 我们可以通过npm安装iScroll,也可以直接引入…

    other 2023年6月26日
    00
  • mysql中数据统计的技巧备忘录

    MySQL中数据统计的技巧备忘录 数据统计是数据库应用的重要领域之一。MySQL中可以使用很多种方法实现数据统计,本篇备忘录总结了一些值得掌握的MySQL数据统计技巧,并提供了示例说明。 聚合函数 MySQL提供了很多方便的聚合函数,如COUNT、SUM、AVG、MAX、MIN等。这些函数能够对数据进行简单的统计分析,常用于统计行数、求和、平均值、最大值、最…

    other 2023年6月25日
    00
合作推广
合作推广
分享本页
返回顶部