mirror of
https://github.com/CnTransGroup/EffectiveModernCppChinese.git
synced 2025-01-17 07:30:09 +08:00
deploy: d2f59cdcd4
This commit is contained in:
parent
e5010cc786
commit
a7243ba154
@ -156,7 +156,7 @@
|
||||
<p>在本章的这些小节中,非常重要的一点是要牢记形参永远是<strong>左值</strong>,即使它的类型是一个右值引用。比如,假设</p>
|
||||
<pre><code class="language-c++">void f(Widget&& 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>
|
||||
|
@ -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&)</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&)</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-></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-></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>
|
||||
|
@ -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&)</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&)</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-></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-></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>
|
||||
|
@ -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&)</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&)</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-></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-></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&& 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>
|
||||
|
Loading…
Reference in New Issue
Block a user