This commit is contained in:
y1yang1 2023-03-29 15:14:44 +00:00
parent e5010cc786
commit a7243ba154
4 changed files with 11 additions and 11 deletions

View File

@ -156,7 +156,7 @@
<p>在本章的这些小节中,非常重要的一点是要牢记形参永远是<strong>左值</strong>,即使它的类型是一个右值引用。比如,假设</p>
<pre><code class="language-c++">void f(Widget&amp;&amp; w);
</code></pre>
<p>形参<code>w</code>是一个左值即使它的类型是一个rvalue-reference-to-<code>Widget</code>。(如果这里震惊到你了,请重新回顾从本书<a href="https://github.com/CnTransGroup/EffectiveModernCppChinese/blob/master/src/Introduction.md">简介</a>开始的关于左值和右值的总览。)</p>
<p>形参<code>w</code>是一个左值即使它的类型是一个rvalue-reference-to-<code>Widget</code>。(如果这里震惊到你了,请重新回顾从本书<a href="../Introduction.html">简介</a>开始的关于左值和右值的总览。)</p>
<h2 id="条款二十三理解stdmove和stdforward"><a class="header" href="#条款二十三理解stdmove和stdforward">条款二十三:理解<code>std::move</code><code>std::forward</code></a></h2>
<p><strong>Item 23: Understand <code>std::move</code> and <code>std::forward</code></strong></p>
<p>为了了解<code>std::move</code><code>std::forward</code>,一种有用的方式是从<strong>它们不做什么</strong>这个角度来了解它们。<code>std::move</code>不移动move任何东西<code>std::forward</code>也不转发forward任何东西。在运行时它们不做任何事情。它们不产生任何可执行代码一字节也没有。</p>

View File

@ -200,7 +200,7 @@ someFunc(std::move(wid)); //在这个someFunc调用中w是通过移动
//创建的副本
</code></pre>
<p>右值副本通常由移动构造产生,左值副本通常由拷贝构造产生。如果你仅仅知道一个对象是其他对象的副本,构造这个副本需要花费多大代价是没法说的。比如在上面的代码中,在不知道是用左值还是右值传给<code>someFunc</code>情况下,没法说来创建形参<code>w</code>花费代价有多大。(你必须还要知道移动和拷贝<code>Widget</code>的代价。)</p>
<p>在函数调用中,调用地传入的表达式称为函数的<strong>实参</strong><em>argument</em>)。实参被用来初始化函数的<strong>形参</strong><em>parameter</em>)。在上面第一次调用<code>someFunc</code>中,实参为<code>wid</code>。在第二次调用中,实参是<code>std::move(wid)</code>。两个调用中,形参都是<code>w</code>。实参和形参的区别非常重要,因为形参是左值,而用来初始化形参的实参可能是左值或者右值。这一点尤其与<strong>完美转发</strong><em>perfect forwarding</em>)过程有关,被传给函数的实参以原实参的右值性(<em>rvalueness</em>)或左值性(<em>lvalueness</em>),再被传给第二个函数。(完美转发讨论细节在<a href="https://github.com/kelthuzadx/EffectiveModernCppChinese/blob/master/5.RRefMovSemPerfForw/item30.md">Item30</a>。)</p>
<p>在函数调用中,调用地传入的表达式称为函数的<strong>实参</strong><em>argument</em>)。实参被用来初始化函数的<strong>形参</strong><em>parameter</em>)。在上面第一次调用<code>someFunc</code>中,实参为<code>wid</code>。在第二次调用中,实参是<code>std::move(wid)</code>。两个调用中,形参都是<code>w</code>。实参和形参的区别非常重要,因为形参是左值,而用来初始化形参的实参可能是左值或者右值。这一点尤其与<strong>完美转发</strong><em>perfect forwarding</em>)过程有关,被传给函数的实参以原实参的右值性(<em>rvalueness</em>)或左值性(<em>lvalueness</em>),再被传给第二个函数。(完美转发讨论细节在<a href="./5.RRefMovSemPerfForw/item30.html">Item30</a>。)</p>
<p>设计优良的函数是<strong>异常安全</strong><em>exception safe</em>)的,意味着他们至少提供基本的异常安全保证(即基本保证<em>basic guarantee</em>)。这样的函数保证调用者在异常抛出时,程序不变量保持完整(即没有数据结构是毁坏的),且没有资源泄漏。有强异常安全保证的函数确保调用者在异常产生时,程序保持在调用前的状态。</p>
<p>当我提到“<strong>函数对象</strong>”时,我通常指的是某个支持<code>operator()</code>成员函数的类型的对象。换句话说,这个对象的行为像函数一样。偶尔我用稍微更普遍一些的术语,表示可以用非成员函数语法调用的任何东西(即“<code>fuctionName(arguments)</code>”)。这个广泛定义包括的不仅有支持<code>operator()</code>的对象还有函数和类似C的函数指针。较窄的定义来自于C++98广泛点的定义来自于C++11。将成员函数指针加进来的更深的普遍化产生了我们所知的<strong>可调用对象</strong><em>callable objects</em>。你通常可以忽略其中的微小区别简单地认为函数对象和可调用对象为C++中可以用函数调用语法调用的东西。</p>
<p>通过<em>lambda</em>表达式创建的函数对象称为<strong>闭包</strong><em>closures</em>)。没什么必要去区别<em>lambda</em>表达式和它们创建的闭包,所以我经常把它们统称<em>lambdas</em>。类似地,我几乎不区分<strong>函数模板</strong><em>function templates</em>)(即产生函数的模板)和<strong>模板函数</strong><em>template functions</em>)(即从函数模板产生的函数)。<strong>类模板</strong><em>class templates</em>)和<strong>模板类</strong><em>template classes</em>)同上。</p>
@ -227,10 +227,10 @@ enum class Color
{ Yellow, Red, Blue }; //限域enum定义
</code></pre>
<p>定义也有资格称为声明,所以我倾向于只有声明,除非这个东西有个定义非常重要。</p>
<p>我定义一个函数的<strong>签名</strong><em>signature</em>)为它声明的一部分,这个声明指定了形参类型和返回类型。函数名和形参名不是签名的一部分。在上面的例子中,<code>func</code>的签名是<code>bool(const Widget&amp;)</code>。函数声明中除了形参类型和返回类型之外的元素(比如<code>noexcept</code>或者<code>constexpr</code>,如果存在的话)都被排除在外。(<code>noexcept</code><code>constexpr</code><a href="https://github.com/kelthuzadx/EffectiveModernCppChinese/blob/master/3.MovingToModernCpp/item14.md">Item14</a><a href="https://github.com/kelthuzadx/EffectiveModernCppChinese/blob/master/3.MovingToModernCpp/item15.md">15</a>叙述。)“签名”的官方定义和我的有点不一样,但是对本书来说,我的定义更有用。(官方定义有时排除返回类型。)</p>
<p>我定义一个函数的<strong>签名</strong><em>signature</em>)为它声明的一部分,这个声明指定了形参类型和返回类型。函数名和形参名不是签名的一部分。在上面的例子中,<code>func</code>的签名是<code>bool(const Widget&amp;)</code>。函数声明中除了形参类型和返回类型之外的元素(比如<code>noexcept</code>或者<code>constexpr</code>,如果存在的话)都被排除在外。(<code>noexcept</code><code>constexpr</code><a href="./3.MovingToModernCpp/item14.html">Item14</a><a href="./3.MovingToModernCpp/item15.html">15</a>叙述。)“签名”的官方定义和我的有点不一样,但是对本书来说,我的定义更有用。(官方定义有时排除返回类型。)</p>
<p>新的C++标准保持了旧标准写的代码的有效性,但是偶尔标准化委员会<strong>废弃</strong><em>deprecate</em>)一些特性。这些特性在标准化的“死囚区”中,可能在未来的标准中被移除。编译器可能警告也可能不警告这些废弃特性的使用,但是你应当尽量避免使用它们。它们不仅可能导致将来对移植的头痛,也通常不如来替代它们的新特性。例如,<code>std::auto_ptr</code>在C++11中被废弃因为<code>std::unique_ptr</code>可以做同样的工作,而且只会做的更好。</p>
<p>有时标准说一个操作的结果有<strong>未定义的行为</strong><em>undefined behavior</em>)。这意味着运行时表现是不可预测的,不用说你也想避开这种不确定性。有未定义行为的行动的例子是,在<code>std::vector</code>范围外使用方括号(“<code>[]</code>解引用未初始化的迭代器或者引入数据竞争即有两个或以上线程至少一个是writer同时访问相同的内存位置</p>
<p>我将那些比如从<code>new</code>返回的内置指针(<em>build-in pointers</em>)称为<strong>原始指针</strong><em>raw pointers</em>)。原始指针的“反义词”是<strong>智能指针</strong><em>smart pointers</em>)。智能指针通常重载指针解引用运算符(<code>operator-&gt;</code><code>operator*</code>),但在<a href="https://github.com/kelthuzadx/EffectiveModernCppChinese/blob/master/4.SmartPointers/item20.md">Item20</a>中解释看<code>std::weak_ptr</code>是个例外。</p>
<p>我将那些比如从<code>new</code>返回的内置指针(<em>build-in pointers</em>)称为<strong>原始指针</strong><em>raw pointers</em>)。原始指针的“反义词”是<strong>智能指针</strong><em>smart pointers</em>)。智能指针通常重载指针解引用运算符(<code>operator-&gt;</code><code>operator*</code>),但在<a href="./4.SmartPointers/item20.html">Item20</a>中解释看<code>std::weak_ptr</code>是个例外。</p>
<p>在源代码注释中我有时将“constructor”构造函数缩写为<code>ctor</code>将“destructor”析构函数缩写为<code>dtor</code>。(译者注:但译文中基本都完整翻译了而没使用缩写。)</p>
<h3 id="报告bug提出改进意见"><a class="header" href="#报告bug提出改进意见">报告bug提出改进意见</a></h3>
<p>我尽力将本书写的清晰、准确、富含有用的信息但是当然还有些去做得更好的办法。如果你找到了任何类型的错误技术上的叙述上的语法上的印刷上的等或者有些建议如何改进本书请给我发电子邮件到emc++@aristeia.com。新的印刷给了我改进《Modern Effective C++》的机会,但我也不能解决我不知道的问题!</p>

View File

@ -200,7 +200,7 @@ someFunc(std::move(wid)); //在这个someFunc调用中w是通过移动
//创建的副本
</code></pre>
<p>右值副本通常由移动构造产生,左值副本通常由拷贝构造产生。如果你仅仅知道一个对象是其他对象的副本,构造这个副本需要花费多大代价是没法说的。比如在上面的代码中,在不知道是用左值还是右值传给<code>someFunc</code>情况下,没法说来创建形参<code>w</code>花费代价有多大。(你必须还要知道移动和拷贝<code>Widget</code>的代价。)</p>
<p>在函数调用中,调用地传入的表达式称为函数的<strong>实参</strong><em>argument</em>)。实参被用来初始化函数的<strong>形参</strong><em>parameter</em>)。在上面第一次调用<code>someFunc</code>中,实参为<code>wid</code>。在第二次调用中,实参是<code>std::move(wid)</code>。两个调用中,形参都是<code>w</code>。实参和形参的区别非常重要,因为形参是左值,而用来初始化形参的实参可能是左值或者右值。这一点尤其与<strong>完美转发</strong><em>perfect forwarding</em>)过程有关,被传给函数的实参以原实参的右值性(<em>rvalueness</em>)或左值性(<em>lvalueness</em>),再被传给第二个函数。(完美转发讨论细节在<a href="https://github.com/kelthuzadx/EffectiveModernCppChinese/blob/master/5.RRefMovSemPerfForw/item30.md">Item30</a>。)</p>
<p>在函数调用中,调用地传入的表达式称为函数的<strong>实参</strong><em>argument</em>)。实参被用来初始化函数的<strong>形参</strong><em>parameter</em>)。在上面第一次调用<code>someFunc</code>中,实参为<code>wid</code>。在第二次调用中,实参是<code>std::move(wid)</code>。两个调用中,形参都是<code>w</code>。实参和形参的区别非常重要,因为形参是左值,而用来初始化形参的实参可能是左值或者右值。这一点尤其与<strong>完美转发</strong><em>perfect forwarding</em>)过程有关,被传给函数的实参以原实参的右值性(<em>rvalueness</em>)或左值性(<em>lvalueness</em>),再被传给第二个函数。(完美转发讨论细节在<a href="./5.RRefMovSemPerfForw/item30.html">Item30</a>。)</p>
<p>设计优良的函数是<strong>异常安全</strong><em>exception safe</em>)的,意味着他们至少提供基本的异常安全保证(即基本保证<em>basic guarantee</em>)。这样的函数保证调用者在异常抛出时,程序不变量保持完整(即没有数据结构是毁坏的),且没有资源泄漏。有强异常安全保证的函数确保调用者在异常产生时,程序保持在调用前的状态。</p>
<p>当我提到“<strong>函数对象</strong>”时,我通常指的是某个支持<code>operator()</code>成员函数的类型的对象。换句话说,这个对象的行为像函数一样。偶尔我用稍微更普遍一些的术语,表示可以用非成员函数语法调用的任何东西(即“<code>fuctionName(arguments)</code>”)。这个广泛定义包括的不仅有支持<code>operator()</code>的对象还有函数和类似C的函数指针。较窄的定义来自于C++98广泛点的定义来自于C++11。将成员函数指针加进来的更深的普遍化产生了我们所知的<strong>可调用对象</strong><em>callable objects</em>。你通常可以忽略其中的微小区别简单地认为函数对象和可调用对象为C++中可以用函数调用语法调用的东西。</p>
<p>通过<em>lambda</em>表达式创建的函数对象称为<strong>闭包</strong><em>closures</em>)。没什么必要去区别<em>lambda</em>表达式和它们创建的闭包,所以我经常把它们统称<em>lambdas</em>。类似地,我几乎不区分<strong>函数模板</strong><em>function templates</em>)(即产生函数的模板)和<strong>模板函数</strong><em>template functions</em>)(即从函数模板产生的函数)。<strong>类模板</strong><em>class templates</em>)和<strong>模板类</strong><em>template classes</em>)同上。</p>
@ -227,10 +227,10 @@ enum class Color
{ Yellow, Red, Blue }; //限域enum定义
</code></pre>
<p>定义也有资格称为声明,所以我倾向于只有声明,除非这个东西有个定义非常重要。</p>
<p>我定义一个函数的<strong>签名</strong><em>signature</em>)为它声明的一部分,这个声明指定了形参类型和返回类型。函数名和形参名不是签名的一部分。在上面的例子中,<code>func</code>的签名是<code>bool(const Widget&amp;)</code>。函数声明中除了形参类型和返回类型之外的元素(比如<code>noexcept</code>或者<code>constexpr</code>,如果存在的话)都被排除在外。(<code>noexcept</code><code>constexpr</code><a href="https://github.com/kelthuzadx/EffectiveModernCppChinese/blob/master/3.MovingToModernCpp/item14.md">Item14</a><a href="https://github.com/kelthuzadx/EffectiveModernCppChinese/blob/master/3.MovingToModernCpp/item15.md">15</a>叙述。)“签名”的官方定义和我的有点不一样,但是对本书来说,我的定义更有用。(官方定义有时排除返回类型。)</p>
<p>我定义一个函数的<strong>签名</strong><em>signature</em>)为它声明的一部分,这个声明指定了形参类型和返回类型。函数名和形参名不是签名的一部分。在上面的例子中,<code>func</code>的签名是<code>bool(const Widget&amp;)</code>。函数声明中除了形参类型和返回类型之外的元素(比如<code>noexcept</code>或者<code>constexpr</code>,如果存在的话)都被排除在外。(<code>noexcept</code><code>constexpr</code><a href="./3.MovingToModernCpp/item14.html">Item14</a><a href="./3.MovingToModernCpp/item15.html">15</a>叙述。)“签名”的官方定义和我的有点不一样,但是对本书来说,我的定义更有用。(官方定义有时排除返回类型。)</p>
<p>新的C++标准保持了旧标准写的代码的有效性,但是偶尔标准化委员会<strong>废弃</strong><em>deprecate</em>)一些特性。这些特性在标准化的“死囚区”中,可能在未来的标准中被移除。编译器可能警告也可能不警告这些废弃特性的使用,但是你应当尽量避免使用它们。它们不仅可能导致将来对移植的头痛,也通常不如来替代它们的新特性。例如,<code>std::auto_ptr</code>在C++11中被废弃因为<code>std::unique_ptr</code>可以做同样的工作,而且只会做的更好。</p>
<p>有时标准说一个操作的结果有<strong>未定义的行为</strong><em>undefined behavior</em>)。这意味着运行时表现是不可预测的,不用说你也想避开这种不确定性。有未定义行为的行动的例子是,在<code>std::vector</code>范围外使用方括号(“<code>[]</code>解引用未初始化的迭代器或者引入数据竞争即有两个或以上线程至少一个是writer同时访问相同的内存位置</p>
<p>我将那些比如从<code>new</code>返回的内置指针(<em>build-in pointers</em>)称为<strong>原始指针</strong><em>raw pointers</em>)。原始指针的“反义词”是<strong>智能指针</strong><em>smart pointers</em>)。智能指针通常重载指针解引用运算符(<code>operator-&gt;</code><code>operator*</code>),但在<a href="https://github.com/kelthuzadx/EffectiveModernCppChinese/blob/master/4.SmartPointers/item20.md">Item20</a>中解释看<code>std::weak_ptr</code>是个例外。</p>
<p>我将那些比如从<code>new</code>返回的内置指针(<em>build-in pointers</em>)称为<strong>原始指针</strong><em>raw pointers</em>)。原始指针的“反义词”是<strong>智能指针</strong><em>smart pointers</em>)。智能指针通常重载指针解引用运算符(<code>operator-&gt;</code><code>operator*</code>),但在<a href="./4.SmartPointers/item20.html">Item20</a>中解释看<code>std::weak_ptr</code>是个例外。</p>
<p>在源代码注释中我有时将“constructor”构造函数缩写为<code>ctor</code>将“destructor”析构函数缩写为<code>dtor</code>。(译者注:但译文中基本都完整翻译了而没使用缩写。)</p>
<h3 id="报告bug提出改进意见"><a class="header" href="#报告bug提出改进意见">报告bug提出改进意见</a></h3>
<p>我尽力将本书写的清晰、准确、富含有用的信息但是当然还有些去做得更好的办法。如果你找到了任何类型的错误技术上的叙述上的语法上的印刷上的等或者有些建议如何改进本书请给我发电子邮件到emc++@aristeia.com。新的印刷给了我改进《Modern Effective C++》的机会,但我也不能解决我不知道的问题!</p>

View File

@ -201,7 +201,7 @@ someFunc(std::move(wid)); //在这个someFunc调用中w是通过移动
//创建的副本
</code></pre>
<p>右值副本通常由移动构造产生,左值副本通常由拷贝构造产生。如果你仅仅知道一个对象是其他对象的副本,构造这个副本需要花费多大代价是没法说的。比如在上面的代码中,在不知道是用左值还是右值传给<code>someFunc</code>情况下,没法说来创建形参<code>w</code>花费代价有多大。(你必须还要知道移动和拷贝<code>Widget</code>的代价。)</p>
<p>在函数调用中,调用地传入的表达式称为函数的<strong>实参</strong><em>argument</em>)。实参被用来初始化函数的<strong>形参</strong><em>parameter</em>)。在上面第一次调用<code>someFunc</code>中,实参为<code>wid</code>。在第二次调用中,实参是<code>std::move(wid)</code>。两个调用中,形参都是<code>w</code>。实参和形参的区别非常重要,因为形参是左值,而用来初始化形参的实参可能是左值或者右值。这一点尤其与<strong>完美转发</strong><em>perfect forwarding</em>)过程有关,被传给函数的实参以原实参的右值性(<em>rvalueness</em>)或左值性(<em>lvalueness</em>),再被传给第二个函数。(完美转发讨论细节在<a href="https://github.com/kelthuzadx/EffectiveModernCppChinese/blob/master/5.RRefMovSemPerfForw/item30.md">Item30</a>。)</p>
<p>在函数调用中,调用地传入的表达式称为函数的<strong>实参</strong><em>argument</em>)。实参被用来初始化函数的<strong>形参</strong><em>parameter</em>)。在上面第一次调用<code>someFunc</code>中,实参为<code>wid</code>。在第二次调用中,实参是<code>std::move(wid)</code>。两个调用中,形参都是<code>w</code>。实参和形参的区别非常重要,因为形参是左值,而用来初始化形参的实参可能是左值或者右值。这一点尤其与<strong>完美转发</strong><em>perfect forwarding</em>)过程有关,被传给函数的实参以原实参的右值性(<em>rvalueness</em>)或左值性(<em>lvalueness</em>),再被传给第二个函数。(完美转发讨论细节在<a href="./5.RRefMovSemPerfForw/item30.html">Item30</a>。)</p>
<p>设计优良的函数是<strong>异常安全</strong><em>exception safe</em>)的,意味着他们至少提供基本的异常安全保证(即基本保证<em>basic guarantee</em>)。这样的函数保证调用者在异常抛出时,程序不变量保持完整(即没有数据结构是毁坏的),且没有资源泄漏。有强异常安全保证的函数确保调用者在异常产生时,程序保持在调用前的状态。</p>
<p>当我提到“<strong>函数对象</strong>”时,我通常指的是某个支持<code>operator()</code>成员函数的类型的对象。换句话说,这个对象的行为像函数一样。偶尔我用稍微更普遍一些的术语,表示可以用非成员函数语法调用的任何东西(即“<code>fuctionName(arguments)</code>”)。这个广泛定义包括的不仅有支持<code>operator()</code>的对象还有函数和类似C的函数指针。较窄的定义来自于C++98广泛点的定义来自于C++11。将成员函数指针加进来的更深的普遍化产生了我们所知的<strong>可调用对象</strong><em>callable objects</em>。你通常可以忽略其中的微小区别简单地认为函数对象和可调用对象为C++中可以用函数调用语法调用的东西。</p>
<p>通过<em>lambda</em>表达式创建的函数对象称为<strong>闭包</strong><em>closures</em>)。没什么必要去区别<em>lambda</em>表达式和它们创建的闭包,所以我经常把它们统称<em>lambdas</em>。类似地,我几乎不区分<strong>函数模板</strong><em>function templates</em>)(即产生函数的模板)和<strong>模板函数</strong><em>template functions</em>)(即从函数模板产生的函数)。<strong>类模板</strong><em>class templates</em>)和<strong>模板类</strong><em>template classes</em>)同上。</p>
@ -228,10 +228,10 @@ enum class Color
{ Yellow, Red, Blue }; //限域enum定义
</code></pre>
<p>定义也有资格称为声明,所以我倾向于只有声明,除非这个东西有个定义非常重要。</p>
<p>我定义一个函数的<strong>签名</strong><em>signature</em>)为它声明的一部分,这个声明指定了形参类型和返回类型。函数名和形参名不是签名的一部分。在上面的例子中,<code>func</code>的签名是<code>bool(const Widget&amp;)</code>。函数声明中除了形参类型和返回类型之外的元素(比如<code>noexcept</code>或者<code>constexpr</code>,如果存在的话)都被排除在外。(<code>noexcept</code><code>constexpr</code><a href="https://github.com/kelthuzadx/EffectiveModernCppChinese/blob/master/3.MovingToModernCpp/item14.md">Item14</a><a href="https://github.com/kelthuzadx/EffectiveModernCppChinese/blob/master/3.MovingToModernCpp/item15.md">15</a>叙述。)“签名”的官方定义和我的有点不一样,但是对本书来说,我的定义更有用。(官方定义有时排除返回类型。)</p>
<p>我定义一个函数的<strong>签名</strong><em>signature</em>)为它声明的一部分,这个声明指定了形参类型和返回类型。函数名和形参名不是签名的一部分。在上面的例子中,<code>func</code>的签名是<code>bool(const Widget&amp;)</code>。函数声明中除了形参类型和返回类型之外的元素(比如<code>noexcept</code>或者<code>constexpr</code>,如果存在的话)都被排除在外。(<code>noexcept</code><code>constexpr</code><a href="./3.MovingToModernCpp/item14.html">Item14</a><a href="./3.MovingToModernCpp/item15.html">15</a>叙述。)“签名”的官方定义和我的有点不一样,但是对本书来说,我的定义更有用。(官方定义有时排除返回类型。)</p>
<p>新的C++标准保持了旧标准写的代码的有效性,但是偶尔标准化委员会<strong>废弃</strong><em>deprecate</em>)一些特性。这些特性在标准化的“死囚区”中,可能在未来的标准中被移除。编译器可能警告也可能不警告这些废弃特性的使用,但是你应当尽量避免使用它们。它们不仅可能导致将来对移植的头痛,也通常不如来替代它们的新特性。例如,<code>std::auto_ptr</code>在C++11中被废弃因为<code>std::unique_ptr</code>可以做同样的工作,而且只会做的更好。</p>
<p>有时标准说一个操作的结果有<strong>未定义的行为</strong><em>undefined behavior</em>)。这意味着运行时表现是不可预测的,不用说你也想避开这种不确定性。有未定义行为的行动的例子是,在<code>std::vector</code>范围外使用方括号(“<code>[]</code>解引用未初始化的迭代器或者引入数据竞争即有两个或以上线程至少一个是writer同时访问相同的内存位置</p>
<p>我将那些比如从<code>new</code>返回的内置指针(<em>build-in pointers</em>)称为<strong>原始指针</strong><em>raw pointers</em>)。原始指针的“反义词”是<strong>智能指针</strong><em>smart pointers</em>)。智能指针通常重载指针解引用运算符(<code>operator-&gt;</code><code>operator*</code>),但在<a href="https://github.com/kelthuzadx/EffectiveModernCppChinese/blob/master/4.SmartPointers/item20.md">Item20</a>中解释看<code>std::weak_ptr</code>是个例外。</p>
<p>我将那些比如从<code>new</code>返回的内置指针(<em>build-in pointers</em>)称为<strong>原始指针</strong><em>raw pointers</em>)。原始指针的“反义词”是<strong>智能指针</strong><em>smart pointers</em>)。智能指针通常重载指针解引用运算符(<code>operator-&gt;</code><code>operator*</code>),但在<a href="./4.SmartPointers/item20.html">Item20</a>中解释看<code>std::weak_ptr</code>是个例外。</p>
<p>在源代码注释中我有时将“constructor”构造函数缩写为<code>ctor</code>将“destructor”析构函数缩写为<code>dtor</code>。(译者注:但译文中基本都完整翻译了而没使用缩写。)</p>
<h3 id="报告bug提出改进意见"><a class="header" href="#报告bug提出改进意见">报告bug提出改进意见</a></h3>
<p>我尽力将本书写的清晰、准确、富含有用的信息但是当然还有些去做得更好的办法。如果你找到了任何类型的错误技术上的叙述上的语法上的印刷上的等或者有些建议如何改进本书请给我发电子邮件到emc++@aristeia.com。新的印刷给了我改进《Modern Effective C++》的机会,但我也不能解决我不知道的问题!</p>
@ -3238,7 +3238,7 @@ w1 = std::move(w2); //移动赋值w1
<p>在本章的这些小节中,非常重要的一点是要牢记形参永远是<strong>左值</strong>,即使它的类型是一个右值引用。比如,假设</p>
<pre><code class="language-c++">void f(Widget&amp;&amp; w);
</code></pre>
<p>形参<code>w</code>是一个左值即使它的类型是一个rvalue-reference-to-<code>Widget</code>。(如果这里震惊到你了,请重新回顾从本书<a href="https://github.com/CnTransGroup/EffectiveModernCppChinese/blob/master/src/Introduction.md">简介</a>开始的关于左值和右值的总览。)</p>
<p>形参<code>w</code>是一个左值即使它的类型是一个rvalue-reference-to-<code>Widget</code>。(如果这里震惊到你了,请重新回顾从本书<a href="5.RRefMovSemPerfForw/../Introduction.html">简介</a>开始的关于左值和右值的总览。)</p>
<h2 id="条款二十三理解stdmove和stdforward"><a class="header" href="#条款二十三理解stdmove和stdforward">条款二十三:理解<code>std::move</code><code>std::forward</code></a></h2>
<p><strong>Item 23: Understand <code>std::move</code> and <code>std::forward</code></strong></p>
<p>为了了解<code>std::move</code><code>std::forward</code>,一种有用的方式是从<strong>它们不做什么</strong>这个角度来了解它们。<code>std::move</code>不移动move任何东西<code>std::forward</code>也不转发forward任何东西。在运行时它们不做任何事情。它们不产生任何可执行代码一字节也没有。</p>