- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章C++11 shared_ptr 与 make_shared源码剖析详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
所谓智能指针,可以从字面上理解为“智能”的指针。具体来讲,智能指针和普通指针的用法是相似的,不同之处在于,智能指针可以在适当时机自动释放分配的内存。也就是说,使用智能指针可以很好地避免“忘记释放内存而导致内存泄漏”问题出现。由此可见,C++ 也逐渐开始支持垃圾回收机制了,尽管目前支持程度还有限.
c++11 中发布了shared_ptr、unique_ptr、weak_ptr 用以资源的管理,都是定义在memory 这个头文件中.
std::shared_ptr
允许多个shared_ptr 实例指向同一个对象,通过计数管理;std::unique_ptr
是独占对象;weak_ptr
是辅助类,是一种弱引用,指向shared_ptr 所管理的对象。
1
|
#include <memory>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
constexpr shared_ptr() noexcept;
template
<
class
Y>
explicit
shared_ptr(Y* p);
template
<
class
Y,
class
D> shared_ptr(Y* p, D d);
template
<
class
Y,
class
D,
class
A> shared_ptr(Y* p, D d, A a);
template
<
class
D> shared_ptr(nullptr_t p, D d);
template
<
class
D,
class
A> shared_ptr(nullptr_t p, D d, A a);
template
<
class
Y> shared_ptr(
const
shared_ptr<Y>& r, T *p) noexcept;
shared_ptr(
const
shared_ptr& r) noexcept;
template
<
class
Y> shared_ptr(
const
shared_ptr<Y>& r) noexcept;
shared_ptr(shared_ptr&& r) noexcept;
template
<
class
Y> shared_ptr(shared_ptr<Y>&& r) noexcept;
template
<
class
Y>
explicit
shared_ptr(
const
weak_ptr<Y>& r);
template
<
class
Y> shared_ptr(auto_ptr<Y>&& r);
// removed in C++17
template
<
class
Y,
class
D> shared_ptr(unique_ptr<Y, D>&& r);
shared_ptr(nullptr_t) : shared_ptr() { }
|
构造函数比较多啊,抽一个看看源码.
1
2
3
4
5
6
7
8
9
|
template
<
class
_Tp>
inline
shared_ptr<_Tp>::shared_ptr(shared_ptr&& __r) _NOEXCEPT
: __ptr_(__r.__ptr_),
__cntrl_(__r.__cntrl_)
{
__r.__ptr_ = 0;
__r.__cntrl_ = 0;
}
|
大概知道,shared_ptr 中存放一个对象的指针__ptr_ 和用以计数的__cntrl_,这两是shared_ptr 的私有成员变量:
1
2
3
4
5
6
7
8
9
10
|
template
<
class
_Tp>
class
shared_ptr {
typedef
_Tp element_type;
private
:
element_type* __ptr_;
__shared_weak_count* __cntrl_;
...
}
|
另外,移动构造函数因为只是move,所以只是将旧的shared_ptr 转移到新的里.
1
2
3
4
5
6
7
8
9
|
template
<
class
_Tp>
inline
shared_ptr<_Tp>::shared_ptr(
const
shared_ptr& __r) _NOEXCEPT
: __ptr_(__r.__ptr_),
__cntrl_(__r.__cntrl_)
{
if
(__cntrl_)
__cntrl_->__add_shared();
}
|
与移动构造相同,shared_ptr 实例,需要从参数中获得__ptr_ 和 __cntrl.
但是,与移动构造函数不同的是,拷贝构造时增加对象计数的.
下面举例shared_ptr 通常的创建方式:
1
2
3
4
5
|
std::shared_ptr<int> p1; //不传入任何实参
std::shared_ptr<int> p2(nullptr); //传入空指针 nullptr
std::shared_ptr<int> p3(new int(10)); //指定指针为参数
std::shared_ptr<int> p4(p3); //或者 std::shared_ptr<int> p4 = p3;
std::shared_ptr<int> p5(std::move(p4)); //或者 std::shared_ptr<int> p5 = std::move(p4);
|
1
2
3
4
5
6
|
shared_ptr& operator=(
const
shared_ptr& r) noexcept;
template
<
class
Y> shared_ptr& operator=(
const
shared_ptr<Y>& r) noexcept;
shared_ptr& operator=(shared_ptr&& r) noexcept;
template
<
class
Y> shared_ptr& operator=(shared_ptr<Y>&& r);
template
<
class
Y> shared_ptr& operator=(auto_ptr<Y>&& r);
// removed in C++17
template
<
class
Y,
class
D> shared_ptr& operator=(unique_ptr<Y, D>&& r);
|
1
2
3
4
5
|
void
swap(shared_ptr& r) noexcept;
void
reset() noexcept;
template
<
class
Y>
void
reset(Y* p);
template
<
class
Y,
class
D>
void
reset(Y* p, D d);
template
<
class
Y,
class
D,
class
A>
void
reset(Y* p, D d, A a);
|
reset 基本上是对应构造 。
1
2
3
4
5
6
|
T* get()
const
noexcept;
T& operator*()
const
noexcept;
T* operator->()
const
noexcept;
long
use_count()
const
noexcept;
bool
unique()
const
noexcept;
explicit
operator
bool
()
const
noexcept;
|
对于shared_ptr 的成员函数总结如下:
成员方法名 。 |
功 能 。 |
operator=() 。 |
重载赋值号,使得同一类型的 shared_ptr 智能指针可以相互赋值. |
operator*() 。 |
重载 * 号,获取当前 shared_ptr 智能指针对象指向的数据. |
operator->() 。 |
重载 -> 号,当智能指针指向的数据类型为自定义的结构体时,通过 -> 运算符可以获取其内部的指定成员. |
swap() 。 |
交换 2 个相同类型 shared_ptr 智能指针的内容. |
reset() 。 |
当函数没有实参时,该函数会使当前 shared_ptr 所指堆内存的引用计数减 1,同时将当前对象重置为一个空指针;当为函数传递一个新申请的堆内存时,则调用该函数的 shared_ptr 对象会获得该存储空间的所有权,并且引用计数的初始值为 1. |
get() 。 |
获得 shared_ptr 对象内部包含的普通指针. |
use_count() 。 |
返回同当前 shared_ptr 对象(包括它)指向相同的所有 shared_ptr 对象的数量. |
unique() 。 |
判断当前 shared_ptr 对象指向的堆内存,是否不再有其它 shared_ptr 对象再指向它. |
operator bool() 。 |
判断当前 shared_ptr 对象是否为空智能指针,如果是空指针,返回 false;反之,返回 true. |
除了上面的成员函数外,C++11 标准还支持同一类型的 shared_ptr 对象,或者 shared_ptr 和 nullptr 之间,进行 ==,!=,,>= 运算.
注意:
1
2
|
template
<
class
T,
class
... Args>
shared_ptr<T> make_shared(Args&&... args);
|
c++11 中针对shared_ptr 还提供了make_shared 这个外部函数,用以创建一个shared_ptr 实例.
c++ 建议尽可能使用make_shared 创建shared_ptr 实例.
下面来说明下make_shared 的优缺点.
shared_ptr 需要维护引用计数的信息:
如果你通过使用原始的 new 表达式分配对象, 然后传递给 shared_ptr (也就是使用 shared_ptr 的构造函数) 的话, shared_ptr 的实现没有办法选择, 而只能单独的分配控制块:
1
2
|
auto p =
new
widget();
shared_ptr sp1{ p }, sp2{ sp1 };
|
如果选择使用 make_shared 的话, 情况就会变成下面这样
1
|
auto sp1 = make_shared(), sp2{ sp1 };
|
内存分配的动作, 可以一次性完成. 这减少了内存分配的次数, 而内存分配是代价很高的操作.
1
2
3
|
void
F(
const
std::shared_ptr<Lhs>& lhs,
const
std::shared_ptr<Rhs>& rhs) {
/* ... */
}
F(std::shared_ptr<Lhs>(
new
Lhs(
"foo"
)),
std::shared_ptr<Rhs>(
new
Rhs(
"bar"
)));
|
C++ 是不保证参数求值顺序, 以及内部表达式的求值顺序的, 所以可能的执行顺序如下
好了, 现在我们假设在第 2 步的时候, 抛出了一个异常 (比如 out of memory, 总之, Rhs 的构造函数异常了), 那么第一步申请的 Lhs 对象内存泄露了. 这个问题的核心在于, shared_ptr 没有立即获得裸指针 。
我们可以用如下方式来修复这个问题. 。
1
2
3
|
auto lhs = std::shared_ptr<Lhs>(
new
Lhs(
"foo"
));
auto rhs = std::shared_ptr<Rhs>(
new
Rhs(
"bar"
));
F(lhs, rhs);
|
当然, 推荐的做法是使用 std::make_shared 来代替:
1
|
F(std::make_shared<Lhs>(
"foo"
), std::make_shared<Rhs>(
"bar"
));
|
构造函数是保护或私有时,无法使用 make_shared 。
make_shared 虽好, 但也存在一些问题, 比如, 当我想要创建的对象没有公有的构造函数时, make_shared 就无法使用了, 当然我们可以使用一些小技巧来解决这个问题, 比如这里 How do I call ::std::make_shared on a class with only protected or private constructors?
对象的内存可能无法及时回收 。
make_shared 只分配一次内存, 这看起来很好. 减少了内存分配的开销. 问题来了, weak_ptr 会保持控制块(强引用, 以及弱引用的信息)的生命周期, 而因此连带着保持了对象分配的内存, 只有最后一个 weak_ptr 离开作用域时, 内存才会被释放. 原本强引用减为 0 时就可以释放的内存, 现在变为了强引用, 若引用都减为 0 时才能释放, 意外的延迟了内存释放的时间. 这对于内存要求高的场景来说, 是一个需要注意的问题 。
无法像shared_ptr 的构造那样添加一个deleter 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include <iostream>
#include <memory>
using
namespace
std;
int
main()
{
//构建 2 个智能指针
std::shared_ptr<
int
> p1(
new
int
(10));
std::shared_ptr<
int
> p2(p1);
//输出 p2 指向的数据
cout << *p2 << endl;
p1.reset();
//引用计数减 1,p1为空指针
if
(p1) {
cout <<
"p1 不为空"
<< endl;
}
else
{
cout <<
"p1 为空"
<< endl;
}
//以上操作,并不会影响 p2
cout << *p2 << endl;
//判断当前和 p2 同指向的智能指针有多少个
cout << p2.use_count() << endl;
return
0;
}
|
运行结果:
10 p1 为空 10 1 。
C++11 std::shared_ptr总结与使用示例代码详解 。
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我的更多内容! 。
原文链接:https://blog.csdn.net/shift_wwx/article/details/120336234 。
最后此篇关于C++11 shared_ptr 与 make_shared源码剖析详解的文章就讲到这里了,如果你想了解更多关于C++11 shared_ptr 与 make_shared源码剖析详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我的 Django 应用程序在生产过程中变得非常缓慢。可能是由于某些复杂或未索引的查询。 是否有任何类似 django 的方法来分析我的应用程序? 最佳答案 试试 Django Debug Toolb
我正在使用GDownloadUrl将客户端数据发送到服务器。这里是我使用的sode GDownloadUrl( dwnld_url, function(data) {
我一直在尝试开始分析我的 CherryPy 网络服务器,但文档缺乏关于如何设置它的详细信息。我知道我应该能够使用 cherrypy.lib.profiler 作为中间件来安装我的初始服务器。现在,我有
是否有任何 HashMap 实现公开了用于分析 Map 性能的钩子(Hook)方法(平均链长度、最佳/最差/平均访问时间、#rehashes 等)。 在 ~O(1) 访问时间方面使用 HashMap
我想知道是否有可用的技术或工具可以告诉您执行特定方法需要多少时间。 类似于数学/计算机科学中的大 O 符号,可以让您了解算法的复杂性,我想知道代码分析是否有类似的东西。 最佳答案 Profiling是
前面,我们说Ruby没有函数,只有方法.而且实际上有不止一种方法.这一节我们介绍访问控制(accesscontrols). 想想当我们在"最高层"而不是在一个类的定义里定义一个
我有一个用 Visual Basic 编写的大型应用程序6,我需要分析它。有没有类似 ANTS Profiler 的东西但对于 COM应用程序? 最佳答案 我以前用 VBWatch .我对它有很好的体
我做了两个实现来解决 Shikaku 难题。一个使用顶部、左侧、宽度和高度 (TLWH) 作为每个矩形的参数,另一个使用顶部、左侧、底部、右侧 (TLBR)。 出于某种原因,使用 TLBR 的速度要快
如果重要的话,我正在使用 Very Sleepy CS 进行分析。 IPP(Intel's Integrated Performance Primitives)在我的项目中使用,基本上是单次调用: i
我想弄明白这个排列算法是如何工作的: def perm(n, i): if i == len(n) - 1: print n else: for j i
如果 C++ 项目的物理结构有利于编译速度,您将如何获得某种客观的衡量标准?有些人说你应该避免使用模板以获得更好的编译速度,但是如果模板生成大量非冗余目标代码,即使行/秒编译速度不是很好,那也不是很糟
摘自 Robert Sedgewick 和 Kevin Wayne 算法第 4 版 在递归部分基本情况代码是 if(end start) { mid = (start+end
有没有一种简单的方法可以计算一段标准 C 代码实际执行的乘法次数?我想到的代码基本上只是做加法和乘法,主要兴趣是乘法,但也可以计算其他操作的数量。 如果这是一个选项,我想我可以四处用“multiply
我正在编写一个 Netty 应用程序。该应用程序运行在 64 位八核 linux 机器上 Netty 应用程序是一个简单的路由器,它接受请求(传入管道),从请求中读取一些元数据并将数据转发到远程服务(
我希望能得到一些帮助来弄清楚这个异常消息到底对我说了什么。我能够使用调试器将问题缩小到代码中的特定行。但是,我认为更多信息可以更好地找出代码中的实际问题。 public static List
我有一个存储在 USB 拇指驱动器上的 mysql 数据库,该数据库已不可挽回地丢失了其文件分配表。因此,我无法访问整个 ibdata1 文件。不过,我可以找到使用十六进制编辑器使用的记录页面。 所有
我正在使用 jQuery 在单击时显示图像。通过将图像源存储到像这样的变量中,这可以很好地工作.. var theSrc = $(event.target).attr('src'); 然后我可以将这张
我是 R 的新手,但不是 C 的新手。我想看看是否可以为 friend 加速一个包。通常使用 C 我会编译一个设置了 -pg 标志的应用程序,然后将 gmon.out 文件传递给 gprof。 我
在分析我的代码以找出运行缓慢的地方时,我有 3 个功能显然会永远占用,这就是非常困的说法。 这些函数是: ZwDelayExecution 20.460813 20.460813 19.
我正在分析一个应用程序并注意到 52% (195MB) 的内存被 char[] 使用,20% 被 String 使用。这是一个有很多依赖项的大型项目,我刚刚看到它,所以我有几个相关的问题可以帮助我开始
我是一名优秀的程序员,十分优秀!