C++中以独立语句将new对象置入智能指针

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: C++中以独立语句将new对象置入智能指针

1.问题的引入


假设现在有个函数priority()来处理程序的优先级,另一个函数用来在某动态分配的Widget对象上进行某些带有优先权的处理。


1class Widget{
2    // ...
3};
4
5int priority();
6
7void processWidget(std::shared_ptr<Widget> pw, int priority);


现在,有下面的语句调用函数processWidget(),如下所示:


1processWidget(new Widget, priority());


上面的语句调用必然会导致编译器报错,这是由于std::shared_ptr构造函数需要一个原始指针,但该构造函数是一个explicit显式构造函数,无法进行隐式转换。下面调用方式将new Widget原始指针转换为processWidget()所要求的std::shared_ptr。,如下所示:


1processWidget(std::shared_ptr<Widget>(new Widget), priority());


重点来了:即使经过上面一系列的骚操作(即使用对象管理式资源),上面的调用也可能发生内存泄漏


2.内存泄漏发生的原因及解决方法



先看看编译器的工作原理。编译器在生成对processWidget()函数的调用之前,必须先解析其中的参数processWidget()函数接收两个参数,分别是智能指针的构造函数和整型的函数priority()。在调用智能指针构造函数之前,编译器必须先解析其中的new Widget语句。因此,解析该函数的参数分为三步:  

   (1).调用priority();

   (2).执行new Widget;
   (3).调用std::shared_ptr构造函数;


C+编译器以什么样的固定顺序去完成上面的这些事情呢?答案是未知。这和其他语言如Java和C#不同,这两种语言总是以固定的顺序完成函数参数的解析。但是,在C++中可以确定步骤(2)一定先于步骤(3)执行,因为new Widget还要被传递作为std::shared_ptr构造函数的一个实参。然而,对于priority()的调用可以在步骤(1)、步骤(2)、步骤(3)执行。假设编译器选择以步骤(2)执行它,最终的操作次序如下:  

(1).执行new Widget;    (2).调用priority();    (3).调用std::shared_ptr构造函数


但是,如果priority()函数抛出了异常呢?那么从new语句动态分配的资源在到达智能指针构造函数之前就已经泄露了。解决方法:使用一个单独的语句来创建智能指针对象。


1std::shared_ptr<Widget> pw(new Widget);  // 放在单独的语句中
2processWidget(pw, priority());   // 不会泄露资源


编译器是逐语句编译的,通过使用一个单独的语句来构造智能指针对象,编译器就不会随意改动解析顺序,保证了生成的机器代码顺序是异常安全的,以及这样的代码写出来也更加美观。


3.总结



(1) 以独立语句将new对象存储于智能指针内。如果不这样做,一旦异常被抛出,有可能导致难以察觉的内存泄漏。

相关文章
|
14天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
46 4
|
15天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
43 4
|
1月前
|
存储 安全 编译器
在 C++中,引用和指针的区别
在C++中,引用和指针都是用于间接访问对象的工具,但它们有显著区别。引用是对象的别名,必须在定义时初始化且不可重新绑定;指针是一个变量,可以指向不同对象,也可为空。引用更安全,指针更灵活。
|
1月前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
28 4
|
1月前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
25 4
|
1月前
|
存储 编译器 C语言
【C++打怪之路Lv3】-- 类和对象(上)
【C++打怪之路Lv3】-- 类和对象(上)
17 0
|
1天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
14 2
|
8天前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
33 5
|
1月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
22 1
|
1月前
|
存储 编译器 C++
【C++类和对象(下)】——我与C++的不解之缘(五)
【C++类和对象(下)】——我与C++的不解之缘(五)