This commit is contained in:
y1yang0 2024-08-19 06:53:05 +00:00
parent d69eca584d
commit a450c426d3
4 changed files with 4 additions and 4 deletions

View File

@ -256,7 +256,7 @@ private:
<p>了解了动态分配控制块,任意大小的删除器和分配器,虚函数机制,原子性的引用计数修改,你对于<code>std::shared_ptr</code>的热情可能有点消退。可以理解,对每个资源管理问题来说都没有最佳的解决方案。但就它提供的功能来说,<code>std::shared_ptr</code>的开销是非常合理的。在通常情况下,使用默认删除器和默认分配器,使用<code>std::make_shared</code>创建<code>std::shared_ptr</code>产生的控制块只需三个word大小。它的分配基本上是无开销的。开销被并入了指向的对象的分配成本里。细节参见<a href="../4.SmartPointers/item21.html">Item21</a>)。对<code>std::shared_ptr</code>解引用的开销不会比原始指针高。执行需要原子引用计数修改的操作需要承担一两个原子操作开销,这些操作通常都会一一映射到机器指令上,所以即使对比非原子指令来说,原子指令开销较大,但是它们仍然只是单个指令上的。对于每个被<code>std::shared_ptr</code>指向的对象来说,控制块中的虚函数机制产生的开销通常只需要承受一次,即对象销毁的时候。</p>
<p>作为这些轻微开销的交换,你得到了动态分配的资源的生命周期自动管理的好处。大多数时候,比起手动管理,使用<code>std::shared_ptr</code>管理共享性资源都是非常合适的。如果你还在犹豫是否能承受<code>std::shared_ptr</code>带来的开销,那就再想想你是否需要共享所有权。如果独占资源可行或者<strong>可能</strong>可行,用<code>std::unique_ptr</code>是一个更好的选择。它的性能表现更接近于原始指针,并且从<code>std::unique_ptr</code>升级到<code>std::shared_ptr</code>也很容易,因为<code>std::shared_ptr</code>可以从<code>std::unique_ptr</code>上创建。</p>
<p>反之不行。当你的资源由<code>std::shared_ptr</code>管理,现在又想修改资源生命周期管理方式是没有办法的。即使引用计数为一,你也不能重新修改资源所有权,改用<code>std::unique_ptr</code>管理它。资源和指向它的<code>std::shared_ptr</code>的签订的所有权协议是“除非死亡否则永不分开”。不能分离,不能废除,没有特许。</p>
<p><code>std::shared_ptr</code>不能处理的另一个东西是数组。和<code>std::unique_ptr</code>不同的是,<code>std::shared_ptr</code>的API设计之初就是针对单个对象的没有办法<code>std::shared_ptr&lt;T[]&gt;</code>。一次又一次,“聪明”的程序员踌躇于是否该使用<code>std::shared_ptr&lt;T&gt;</code>指向数组,然后传入自定义删除器来删除数组(即<code>delete []</code>)。这可以通过编译,但是是一个糟糕的主意。一方面,<code>std::shared_ptr</code>没有提供<code>operator[]</code>,所以数组索引操作需要借助怪异的指针算术。另一方面,<code>std::shared_ptr</code>支持转换为指向基类的指针,这对于单个对象来说有效,但是当用于数组类型时相当于在类型系统上开洞。(出于这个原因,<code>std::unique_ptr&lt;T[]&gt;</code> API禁止这种转换。更重要的是C++11已经提供了很多内置数组的候选方案比如<code>std::array</code><code>std::vector</code><code>std::string</code>)。声明一个指向傻瓜数组的智能指针(译注:也是”聪明的指针“之意)几乎总是表示着糟糕的设计。</p>
<p><code>std::shared_ptr</code>不能处理的另一个东西是数组。和<code>std::unique_ptr</code>不同的是,<code>std::shared_ptr</code>的API设计之初就是针对单个对象的没有办法<code>std::shared_ptr&lt;T[]&gt;</code>(译者注: 自 C++17 起 std::shared_ptr 可以用于管理动态分配的数组,使用 std::shared_ptr&lt;T[]&gt;一次又一次,“聪明”的程序员踌躇于是否该使用<code>std::shared_ptr&lt;T&gt;</code>指向数组,然后传入自定义删除器来删除数组(即<code>delete []</code>)。这可以通过编译,但是是一个糟糕的主意。一方面,<code>std::shared_ptr</code>没有提供<code>operator[]</code>,所以数组索引操作需要借助怪异的指针算术。另一方面,<code>std::shared_ptr</code>支持转换为指向基类的指针,这对于单个对象来说有效,但是当用于数组类型时相当于在类型系统上开洞。(出于这个原因,<code>std::unique_ptr&lt;T[]&gt;</code> API禁止这种转换。更重要的是C++11已经提供了很多内置数组的候选方案比如<code>std::array</code><code>std::vector</code><code>std::string</code>)。声明一个指向傻瓜数组的智能指针(译注:也是”聪明的指针“之意)几乎总是表示着糟糕的设计。</p>
<p><strong>请记住:</strong></p>
<ul>
<li><code>std::shared_ptr</code>为有共享所有权的任意资源提供一种自动垃圾回收的便捷方式。</li>

View File

@ -2766,7 +2766,7 @@ private:
<p>了解了动态分配控制块,任意大小的删除器和分配器,虚函数机制,原子性的引用计数修改,你对于<code>std::shared_ptr</code>的热情可能有点消退。可以理解,对每个资源管理问题来说都没有最佳的解决方案。但就它提供的功能来说,<code>std::shared_ptr</code>的开销是非常合理的。在通常情况下,使用默认删除器和默认分配器,使用<code>std::make_shared</code>创建<code>std::shared_ptr</code>产生的控制块只需三个word大小。它的分配基本上是无开销的。开销被并入了指向的对象的分配成本里。细节参见<a href="4.SmartPointers/../4.SmartPointers/item21.html">Item21</a>)。对<code>std::shared_ptr</code>解引用的开销不会比原始指针高。执行需要原子引用计数修改的操作需要承担一两个原子操作开销,这些操作通常都会一一映射到机器指令上,所以即使对比非原子指令来说,原子指令开销较大,但是它们仍然只是单个指令上的。对于每个被<code>std::shared_ptr</code>指向的对象来说,控制块中的虚函数机制产生的开销通常只需要承受一次,即对象销毁的时候。</p>
<p>作为这些轻微开销的交换,你得到了动态分配的资源的生命周期自动管理的好处。大多数时候,比起手动管理,使用<code>std::shared_ptr</code>管理共享性资源都是非常合适的。如果你还在犹豫是否能承受<code>std::shared_ptr</code>带来的开销,那就再想想你是否需要共享所有权。如果独占资源可行或者<strong>可能</strong>可行,用<code>std::unique_ptr</code>是一个更好的选择。它的性能表现更接近于原始指针,并且从<code>std::unique_ptr</code>升级到<code>std::shared_ptr</code>也很容易,因为<code>std::shared_ptr</code>可以从<code>std::unique_ptr</code>上创建。</p>
<p>反之不行。当你的资源由<code>std::shared_ptr</code>管理,现在又想修改资源生命周期管理方式是没有办法的。即使引用计数为一,你也不能重新修改资源所有权,改用<code>std::unique_ptr</code>管理它。资源和指向它的<code>std::shared_ptr</code>的签订的所有权协议是“除非死亡否则永不分开”。不能分离,不能废除,没有特许。</p>
<p><code>std::shared_ptr</code>不能处理的另一个东西是数组。和<code>std::unique_ptr</code>不同的是,<code>std::shared_ptr</code>的API设计之初就是针对单个对象的没有办法<code>std::shared_ptr&lt;T[]&gt;</code>。一次又一次,“聪明”的程序员踌躇于是否该使用<code>std::shared_ptr&lt;T&gt;</code>指向数组,然后传入自定义删除器来删除数组(即<code>delete []</code>)。这可以通过编译,但是是一个糟糕的主意。一方面,<code>std::shared_ptr</code>没有提供<code>operator[]</code>,所以数组索引操作需要借助怪异的指针算术。另一方面,<code>std::shared_ptr</code>支持转换为指向基类的指针,这对于单个对象来说有效,但是当用于数组类型时相当于在类型系统上开洞。(出于这个原因,<code>std::unique_ptr&lt;T[]&gt;</code> API禁止这种转换。更重要的是C++11已经提供了很多内置数组的候选方案比如<code>std::array</code><code>std::vector</code><code>std::string</code>)。声明一个指向傻瓜数组的智能指针(译注:也是”聪明的指针“之意)几乎总是表示着糟糕的设计。</p>
<p><code>std::shared_ptr</code>不能处理的另一个东西是数组。和<code>std::unique_ptr</code>不同的是,<code>std::shared_ptr</code>的API设计之初就是针对单个对象的没有办法<code>std::shared_ptr&lt;T[]&gt;</code>(译者注: 自 C++17 起 std::shared_ptr 可以用于管理动态分配的数组,使用 std::shared_ptr&lt;T[]&gt;一次又一次,“聪明”的程序员踌躇于是否该使用<code>std::shared_ptr&lt;T&gt;</code>指向数组,然后传入自定义删除器来删除数组(即<code>delete []</code>)。这可以通过编译,但是是一个糟糕的主意。一方面,<code>std::shared_ptr</code>没有提供<code>operator[]</code>,所以数组索引操作需要借助怪异的指针算术。另一方面,<code>std::shared_ptr</code>支持转换为指向基类的指针,这对于单个对象来说有效,但是当用于数组类型时相当于在类型系统上开洞。(出于这个原因,<code>std::unique_ptr&lt;T[]&gt;</code> API禁止这种转换。更重要的是C++11已经提供了很多内置数组的候选方案比如<code>std::array</code><code>std::vector</code><code>std::string</code>)。声明一个指向傻瓜数组的智能指针(译注:也是”聪明的指针“之意)几乎总是表示着糟糕的设计。</p>
<p><strong>请记住:</strong></p>
<ul>
<li><code>std::shared_ptr</code>为有共享所有权的任意资源提供一种自动垃圾回收的便捷方式。</li>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long