Mor*_*hai 34 c++ shared-ptr c++11
我试图围绕C++ 11的新习语.
似乎至少使用shared_ptr,使用new T()和之间存在实质性差异make_shared<T>().
但是重置共享指针以指向某个新实例的方法呢.以前,我通常会使用reset(new T())会员.但是,这不是因为没有首先使用make_shared()的问题吗?(即它不允许make_shared分配对象,因此它被强制将ref计数放在单独的分配中而不是与T本身相同的分配中?)
是否更好地继续使用:
mysharedptr = make_shared<T>(args...);
Run Code Online (Sandbox Code Playgroud)
或者,还有更好的方法?
并且不应该像make_shared那样重置提供参数的变量转发,这样就可以编写mysharedptr.reset(args ...);?
And*_*owl 35
确实存在很大差异:
shared_ptr<T> sp(new T());
Run Code Online (Sandbox Code Playgroud)
和:
shared_ptr<T> sp = make_shared<T>();
Run Code Online (Sandbox Code Playgroud)
第一个版本执行T对象的分配,然后执行单独的分配以创建引用计数器.第二个版本为对象和引用计数器执行一次单独分配,将它们放在连续的内存区域中,从而减少内存开销.
此外,一些实现能够执行进一步的空间优化make_shared<>(参见MS的实现完成的"我们知道你住的地方"优化).
但是,这不是make_shared<>存在的唯一原因.基于显式的版本new T()在某些情况下不是异常安全的,尤其是在调用接受a的函数时shared_ptr.
void f(shared_ptr<T> sp1, shared_ptr<T> sp2);
...
f(shared_ptr<T>(new T()), shared_ptr<T>(new T()))
Run Code Online (Sandbox Code Playgroud)
这里,编译器可以计算第一个new T()表达式,然后计算第二个new T()表达式,然后构造相应的shared_ptr<>对象.但是如果第二个分配在第一个分配的对象绑定到它之前导致异常shared_ptr<>怎么办?它会被泄露.有make_shared<>(),这是不可能的:
f(make_shared<T>(), make_shared<T>())
Run Code Online (Sandbox Code Playgroud)
因为已分配的对象绑定到shared_ptr<>每个函数调用中的相应对象make_shared<>(),所以此调用是异常安全的.这是为什么new除非你真的知道自己在做什么,否则永远不应该使用裸体的另一个原因.(*)
考虑到你的评论reset(),你是正确的观察reset(new T())将对计数器和对象执行单独的分配,就像在shared_ptr<>将原始指针作为参数传递时new的构造将执行单独的分配一样.因此,使用赋值make_shared<>是优选的(甚至是诸如此类的陈述reset(make_shared<T>())).
无论是否reset()应该支持可变参数列表,这可能更像是一种OpenOverflow不适合的公开讨论.
(*)有一些情况仍然需要它.例如,C++标准库缺少相应的make_unique<>功能unique_ptr,因此您必须自己编写一个.另一种情况是当你不希望在一个内存块上分配对象和计数器时,因为对象的弱指针的存在将阻止整个块被释放,即使没有更多拥有该对象的指针存在.
正确,reset(new T...)遭受所有问题shared_ptr(new T...); 它将导致双重分配并且也是非异常安全的(泄漏的可能性不大,除非在其中bad_alloc发生reset).
reset被记录为等同于shared_ptr<T>(ptr).swap(*this),所以你也可以写:
make_shared<T>(args...).swap(mysharedptr);
Run Code Online (Sandbox Code Playgroud)
赋值来自make_shared<T>几乎相等,唯一的区别是删除旧的T和破坏临时的相对顺序shared_ptr,这是不可观察的.
| 归档时间: |
|
| 查看次数: |
10489 次 |
| 最近记录: |