为什么共享指针分配会"交换"?
Why shared pointer assignment does 'swap'?
正如我所理解的,当分配共享ptr时,其行为应该像:
a) if (--this->count == 0) { release this->count and this->obj }
b) this->count = r->count, this->obj = r->obj;
助推只是
shared_ptr & operator=( shared_ptr const & r ) BOOST_NOEXCEPT
{
this_type(r).swap(*this);
return *this;
}
那么,交换背后的魔力是什么?为什么它有效?
a) 如果(--this->count==0){释放this->count和this->obj}
否,shared_ptr
保留两个计数,一个用于对象,一个则用于包含参考计数的控制块。当第一个达到零时,释放this->obj
,当第二个达到零时释放this->count
(和第二个计数)。
b) this->count=r->count,this->obj=r->obj;
不,您缺少引用计数增量。此外,正如Yakk的回答所指出的,你必须先检查自分配或增加右侧,以避免在自分配时错误地破坏对象。
所以你的理解是不完整/不正确的,但如果你仔细阅读Boost代码,你会发现它做得完全正确。它增加了r
对象上的引用计数,交换了所有必要的值,然后减少了*this
原始值的引用计数。
增加引用计数的步骤已经在副本构造函数中实现,因此它会重新使用它。
交换所有必要值的步骤已经在swap
成员中实现,因此它使用该步骤。
减少引用计数(并在需要时释放任何内容)的步骤已经由析构函数完成,所以它使用它。
这是极好的代码重用。另一种选择是重复复制构造函数、交换成员和析构函数中的所有相同代码,这将是冗余的并且容易出错。
这是复制交换习惯用法。它并不总是有效的,但在这种情况下是有效的
要分配ref count对象,首先(a)增加右手边的ref count,然后(b)减少左手边的ref计数,以及(c)将rhs的状态存储在lhs上。
只有在可能发生异常的情况下,(b)和(c)的顺序才重要,但如果存在自分配(或等效),则(a)必须发生在(b)之前。
复制交换习惯用法是这样做的:
- (1) 将rhs复制到临时
- (2) 用临时(包含rhs状态的副本)交换lhs状态
- (3) 销毁临时这在(1)中做了(a),然后在(2)中做(c),然后是在(3)中做的(b)。它以一种特别安全的异常方式进行:代码处于"奇怪"状态的唯一时间是在交换中,并且交换很容易进行异常验证
拷贝交换可以作为一种通用的易于编写的分配,但它不重用lhs的内部资源,这可能会降低成本。在这种情况下,这并不重要,因为lhs的内部资源是指向共享状态的指针。
在赋值运算符作用域(结束的}
)结束时,原始sptr对象的引用计数将减少一,因为r
不再指向它。因此,它在功能上正是您上面描述的。
- 将数组的地址分配给变量并删除
- vector.resize()中的分配错误
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- Win32编译器选项和内存分配
- 函数中堆分配的效果与缺少堆分配的情况
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 获取字符串的长度并将其分配给数组
- C++ - 没有自定义交换功能的移动分配运算符?
- C++移动分配可防止复制交换习惯用法
- 为什么标准在移动分配运算符中使用交换?
- 向量交换的向量中的分割故障,将内存分配给指针为向量的向量
- 在c++中编写交换函数以重新分配结构数组中的成员值
- 为什么共享指针分配会"交换"?
- 使用复制和交换习惯用法,复制对象的析构函数如何不解除分配指向内存
- 移动分配与标准复制和交换不兼容
- 交换两个阵列而不完全分配第三个 (C++)
- 使用公用指针交换指向已分配内存的指针
- 消息分配运算符未使用交换
- 使用无分配交换有什么明显的缺点吗