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

yizhihongxing

深入学习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日

相关文章

  • Java数据结构实现折半查找的算法过程解析

    Java数据结构实现折半查找的算法过程解析 算法概述 折半查找又被称为二分查找,是一种用于在有序数组中查找指定元素的算法。折半查找的核心思想是利用有序数组的有序性,通过反复将搜索区间折半的方式来定位目标元素。因为每次都取搜索区间中间的值进行比较,所以其时间复杂度为O(log n),是一种高效的查找算法。 算法实现步骤 折半查找过程可以用递归或迭代两种方式实现…

    other 2023年6月27日
    00
  • 浅析Java ClassName.this中类名.this关键字的理解

    浅析Java ClassName.this中类名.this关键字的理解 在Java中,当类中有内部类的时候,在内部类中可能会出现与外部类同名的成员变量或方法,此时就需要使用类名.this关键字来引用外部类的成员。 定义 ClassName.this可以指向外部类的实例。在内部类中使用ClassName.this引用的是外部类的实例对象。 示例1 在下面的示例…

    other 2023年6月27日
    00
  • Python中sorted()排序与字母大小写的问题

    Python中sorted()排序与字母大小写的问题攻略 在Python中,sorted()函数用于对可迭代对象进行排序。然而,当涉及到字母的排序时,大小写是一个需要考虑的问题。下面是一个详细的攻略,解释了如何在排序过程中处理字母的大小写。 1. 默认情况下的排序 在默认情况下,sorted()函数会根据字母的Unicode码点进行排序。这意味着大写字母会排…

    other 2023年8月17日
    00
  • AngularJS Controller作用域

    AngularJS Controller作用域攻略 AngularJS是一个流行的JavaScript框架,用于构建Web应用程序。在AngularJS中,Controller是一个重要的概念,它用于管理应用程序的数据和逻辑。Controller作用域是指Controller与视图之间的连接,它定义了Controller中可用的变量和函数。 创建Contro…

    other 2023年8月19日
    00
  • 微信公众号开发者账号该怎么申请?

    要申请微信公众号开发者账号,步骤如下: 1. 进入微信公众平台官网 在浏览器中输入 https://mp.weixin.qq.com 并进入微信公众平台官网。 2. 注册微信公众号开发者账号 在微信公众平台官网首页,点击“注册”,进入注册页面。填写邮箱、手机号等相关信息并进行人机验证,最后点击“注册”。 3. 登录微信公众号开发者账号 注册完成后,使用已注册…

    other 2023年6月26日
    00
  • java实现图的邻接表存储结构的两种方式及实例应用详解

    下面就给您详细讲解“java实现图的邻接表存储结构的两种方式及实例应用详解”的完整攻略。 一、什么是图的邻接表存储结构? 图是一种重要的数据结构,主要由顶点和边组成。邻接表存储结构是一种常见的存储图的方式,它采用链表来表示图中的每个顶点及其相邻的顶点。其中,每个顶点对应一个单链表,存储该顶点与其他顶点相邻的边。 邻接表存储结构通常使用数组加链表的方式实现。数…

    other 2023年6月28日
    00
  • div自定义滚动条样式(二)

    div自定义滚动条样式(二)攻略 在本攻略中,我们将详细讲解如何使用CSS和JavaScript自定义div滚动条的样式。我们将提供两个示例,一个是使用样式,另一个是使用代码。 示例1:使用CSS样式 以下是一个使用CSS样式自定义div滚动条的示例: /* 隐藏默认滚动条 */ ::-webkit-scrollbar { display: none; } …

    other 2023年5月8日
    00
  • Springboot配置suffix指定mvc视图的后缀方法

    Spring Boot配置suffix指定MVC视图的后缀方法攻略 在Spring Boot中,我们可以使用suffix属性来指定MVC视图的后缀。这个属性可以让我们更灵活地定义视图的后缀,以适应不同的需求。下面是详细的攻略: 步骤一:在application.properties文件中配置suffix属性 首先,我们需要在application.prope…

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