From a7243ba15400eb12b699889f4286a69b139d3d7e Mon Sep 17 00:00:00 2001 From: y1yang1 Date: Wed, 29 Mar 2023 15:14:44 +0000 Subject: [PATCH] deploy: d2f59cdcd4acec185fbdb32a2364d7ba62727a23 --- 5.RRefMovSemPerfForw/item23.html | 2 +- Introduction.html | 6 +++--- index.html | 6 +++--- print.html | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/5.RRefMovSemPerfForw/item23.html b/5.RRefMovSemPerfForw/item23.html index 507029c..70421ba 100644 --- a/5.RRefMovSemPerfForw/item23.html +++ b/5.RRefMovSemPerfForw/item23.html @@ -156,7 +156,7 @@

在本章的这些小节中,非常重要的一点是要牢记形参永远是左值,即使它的类型是一个右值引用。比如,假设

void f(Widget&& w);
 
-

形参w是一个左值,即使它的类型是一个rvalue-reference-to-Widget。(如果这里震惊到你了,请重新回顾从本书简介开始的关于左值和右值的总览。)

+

形参w是一个左值,即使它的类型是一个rvalue-reference-to-Widget。(如果这里震惊到你了,请重新回顾从本书简介开始的关于左值和右值的总览。)

条款二十三:理解std::movestd::forward

Item 23: Understand std::move and std::forward

为了了解std::movestd::forward,一种有用的方式是从它们不做什么这个角度来了解它们。std::move不移动(move)任何东西,std::forward也不转发(forward)任何东西。在运行时,它们不做任何事情。它们不产生任何可执行代码,一字节也没有。

diff --git a/Introduction.html b/Introduction.html index 7c8e7d5..34ed830 100644 --- a/Introduction.html +++ b/Introduction.html @@ -200,7 +200,7 @@ someFunc(std::move(wid)); //在这个someFunc调用中,w是通过移动 //创建的副本

右值副本通常由移动构造产生,左值副本通常由拷贝构造产生。如果你仅仅知道一个对象是其他对象的副本,构造这个副本需要花费多大代价是没法说的。比如在上面的代码中,在不知道是用左值还是右值传给someFunc情况下,没法说来创建形参w花费代价有多大。(你必须还要知道移动和拷贝Widget的代价。)

-

在函数调用中,调用地传入的表达式称为函数的实参argument)。实参被用来初始化函数的形参parameter)。在上面第一次调用someFunc中,实参为wid。在第二次调用中,实参是std::move(wid)。两个调用中,形参都是w。实参和形参的区别非常重要,因为形参是左值,而用来初始化形参的实参可能是左值或者右值。这一点尤其与完美转发perfect forwarding)过程有关,被传给函数的实参以原实参的右值性(rvalueness)或左值性(lvalueness),再被传给第二个函数。(完美转发讨论细节在Item30。)

+

在函数调用中,调用地传入的表达式称为函数的实参argument)。实参被用来初始化函数的形参parameter)。在上面第一次调用someFunc中,实参为wid。在第二次调用中,实参是std::move(wid)。两个调用中,形参都是w。实参和形参的区别非常重要,因为形参是左值,而用来初始化形参的实参可能是左值或者右值。这一点尤其与完美转发perfect forwarding)过程有关,被传给函数的实参以原实参的右值性(rvalueness)或左值性(lvalueness),再被传给第二个函数。(完美转发讨论细节在Item30。)

设计优良的函数是异常安全exception safe)的,意味着他们至少提供基本的异常安全保证(即基本保证basic guarantee)。这样的函数保证调用者在异常抛出时,程序不变量保持完整(即没有数据结构是毁坏的),且没有资源泄漏。有强异常安全保证的函数确保调用者在异常产生时,程序保持在调用前的状态。

当我提到“函数对象”时,我通常指的是某个支持operator()成员函数的类型的对象。换句话说,这个对象的行为像函数一样。偶尔我用稍微更普遍一些的术语,表示可以用非成员函数语法调用的任何东西(即“fuctionName(arguments)”)。这个广泛定义包括的不仅有支持operator()的对象,还有函数和类似C的函数指针。(较窄的定义来自于C++98,广泛点的定义来自于C++11。)将成员函数指针加进来的更深的普遍化产生了我们所知的可调用对象callable objects)。你通常可以忽略其中的微小区别,简单地认为函数对象和可调用对象为C++中可以用函数调用语法调用的东西。

通过lambda表达式创建的函数对象称为闭包closures)。没什么必要去区别lambda表达式和它们创建的闭包,所以我经常把它们统称lambdas。类似地,我几乎不区分函数模板function templates)(即产生函数的模板)和模板函数template functions)(即从函数模板产生的函数)。类模板class templates)和模板类template classes)同上。

@@ -227,10 +227,10 @@ enum class Color { Yellow, Red, Blue }; //限域enum定义

定义也有资格称为声明,所以我倾向于只有声明,除非这个东西有个定义非常重要。

-

我定义一个函数的签名signature)为它声明的一部分,这个声明指定了形参类型和返回类型。函数名和形参名不是签名的一部分。在上面的例子中,func的签名是bool(const Widget&)。函数声明中除了形参类型和返回类型之外的元素(比如noexcept或者constexpr,如果存在的话)都被排除在外。(noexceptconstexprItem1415叙述。)“签名”的官方定义和我的有点不一样,但是对本书来说,我的定义更有用。(官方定义有时排除返回类型。)

+

我定义一个函数的签名signature)为它声明的一部分,这个声明指定了形参类型和返回类型。函数名和形参名不是签名的一部分。在上面的例子中,func的签名是bool(const Widget&)。函数声明中除了形参类型和返回类型之外的元素(比如noexcept或者constexpr,如果存在的话)都被排除在外。(noexceptconstexprItem1415叙述。)“签名”的官方定义和我的有点不一样,但是对本书来说,我的定义更有用。(官方定义有时排除返回类型。)

新的C++标准保持了旧标准写的代码的有效性,但是偶尔标准化委员会废弃deprecate)一些特性。这些特性在标准化的“死囚区”中,可能在未来的标准中被移除。编译器可能警告也可能不警告这些废弃特性的使用,但是你应当尽量避免使用它们。它们不仅可能导致将来对移植的头痛,也通常不如来替代它们的新特性。例如,std::auto_ptr在C++11中被废弃,因为std::unique_ptr可以做同样的工作,而且只会做的更好。

有时标准说一个操作的结果有未定义的行为undefined behavior)。这意味着运行时表现是不可预测的,不用说你也想避开这种不确定性。有未定义行为的行动的例子是,在std::vector范围外使用方括号(“[]”),解引用未初始化的迭代器,或者引入数据竞争(即有两个或以上线程,至少一个是writer,同时访问相同的内存位置)。

-

我将那些比如从new返回的内置指针(build-in pointers)称为原始指针raw pointers)。原始指针的“反义词”是智能指针smart pointers)。智能指针通常重载指针解引用运算符(operator->operator*),但在Item20中解释看std::weak_ptr是个例外。

+

我将那些比如从new返回的内置指针(build-in pointers)称为原始指针raw pointers)。原始指针的“反义词”是智能指针smart pointers)。智能指针通常重载指针解引用运算符(operator->operator*),但在Item20中解释看std::weak_ptr是个例外。

在源代码注释中,我有时将“constructor”(构造函数)缩写为ctor,将“destructor”(析构函数)缩写为dtor。(译者注:但译文中基本都完整翻译了而没使用缩写。)

报告bug,提出改进意见

我尽力将本书写的清晰、准确、富含有用的信息,但是当然还有些去做得更好的办法。如果你找到了任何类型的错误(技术上的,叙述上的,语法上的,印刷上的等),或者有些建议如何改进本书,请给我发电子邮件到emc++@aristeia.com。新的印刷给了我改进《Modern Effective C++》的机会,但我也不能解决我不知道的问题!

diff --git a/index.html b/index.html index 75c2d6f..07c5da2 100644 --- a/index.html +++ b/index.html @@ -200,7 +200,7 @@ someFunc(std::move(wid)); //在这个someFunc调用中,w是通过移动 //创建的副本

右值副本通常由移动构造产生,左值副本通常由拷贝构造产生。如果你仅仅知道一个对象是其他对象的副本,构造这个副本需要花费多大代价是没法说的。比如在上面的代码中,在不知道是用左值还是右值传给someFunc情况下,没法说来创建形参w花费代价有多大。(你必须还要知道移动和拷贝Widget的代价。)

-

在函数调用中,调用地传入的表达式称为函数的实参argument)。实参被用来初始化函数的形参parameter)。在上面第一次调用someFunc中,实参为wid。在第二次调用中,实参是std::move(wid)。两个调用中,形参都是w。实参和形参的区别非常重要,因为形参是左值,而用来初始化形参的实参可能是左值或者右值。这一点尤其与完美转发perfect forwarding)过程有关,被传给函数的实参以原实参的右值性(rvalueness)或左值性(lvalueness),再被传给第二个函数。(完美转发讨论细节在Item30。)

+

在函数调用中,调用地传入的表达式称为函数的实参argument)。实参被用来初始化函数的形参parameter)。在上面第一次调用someFunc中,实参为wid。在第二次调用中,实参是std::move(wid)。两个调用中,形参都是w。实参和形参的区别非常重要,因为形参是左值,而用来初始化形参的实参可能是左值或者右值。这一点尤其与完美转发perfect forwarding)过程有关,被传给函数的实参以原实参的右值性(rvalueness)或左值性(lvalueness),再被传给第二个函数。(完美转发讨论细节在Item30。)

设计优良的函数是异常安全exception safe)的,意味着他们至少提供基本的异常安全保证(即基本保证basic guarantee)。这样的函数保证调用者在异常抛出时,程序不变量保持完整(即没有数据结构是毁坏的),且没有资源泄漏。有强异常安全保证的函数确保调用者在异常产生时,程序保持在调用前的状态。

当我提到“函数对象”时,我通常指的是某个支持operator()成员函数的类型的对象。换句话说,这个对象的行为像函数一样。偶尔我用稍微更普遍一些的术语,表示可以用非成员函数语法调用的任何东西(即“fuctionName(arguments)”)。这个广泛定义包括的不仅有支持operator()的对象,还有函数和类似C的函数指针。(较窄的定义来自于C++98,广泛点的定义来自于C++11。)将成员函数指针加进来的更深的普遍化产生了我们所知的可调用对象callable objects)。你通常可以忽略其中的微小区别,简单地认为函数对象和可调用对象为C++中可以用函数调用语法调用的东西。

通过lambda表达式创建的函数对象称为闭包closures)。没什么必要去区别lambda表达式和它们创建的闭包,所以我经常把它们统称lambdas。类似地,我几乎不区分函数模板function templates)(即产生函数的模板)和模板函数template functions)(即从函数模板产生的函数)。类模板class templates)和模板类template classes)同上。

@@ -227,10 +227,10 @@ enum class Color { Yellow, Red, Blue }; //限域enum定义

定义也有资格称为声明,所以我倾向于只有声明,除非这个东西有个定义非常重要。

-

我定义一个函数的签名signature)为它声明的一部分,这个声明指定了形参类型和返回类型。函数名和形参名不是签名的一部分。在上面的例子中,func的签名是bool(const Widget&)。函数声明中除了形参类型和返回类型之外的元素(比如noexcept或者constexpr,如果存在的话)都被排除在外。(noexceptconstexprItem1415叙述。)“签名”的官方定义和我的有点不一样,但是对本书来说,我的定义更有用。(官方定义有时排除返回类型。)

+

我定义一个函数的签名signature)为它声明的一部分,这个声明指定了形参类型和返回类型。函数名和形参名不是签名的一部分。在上面的例子中,func的签名是bool(const Widget&)。函数声明中除了形参类型和返回类型之外的元素(比如noexcept或者constexpr,如果存在的话)都被排除在外。(noexceptconstexprItem1415叙述。)“签名”的官方定义和我的有点不一样,但是对本书来说,我的定义更有用。(官方定义有时排除返回类型。)

新的C++标准保持了旧标准写的代码的有效性,但是偶尔标准化委员会废弃deprecate)一些特性。这些特性在标准化的“死囚区”中,可能在未来的标准中被移除。编译器可能警告也可能不警告这些废弃特性的使用,但是你应当尽量避免使用它们。它们不仅可能导致将来对移植的头痛,也通常不如来替代它们的新特性。例如,std::auto_ptr在C++11中被废弃,因为std::unique_ptr可以做同样的工作,而且只会做的更好。

有时标准说一个操作的结果有未定义的行为undefined behavior)。这意味着运行时表现是不可预测的,不用说你也想避开这种不确定性。有未定义行为的行动的例子是,在std::vector范围外使用方括号(“[]”),解引用未初始化的迭代器,或者引入数据竞争(即有两个或以上线程,至少一个是writer,同时访问相同的内存位置)。

-

我将那些比如从new返回的内置指针(build-in pointers)称为原始指针raw pointers)。原始指针的“反义词”是智能指针smart pointers)。智能指针通常重载指针解引用运算符(operator->operator*),但在Item20中解释看std::weak_ptr是个例外。

+

我将那些比如从new返回的内置指针(build-in pointers)称为原始指针raw pointers)。原始指针的“反义词”是智能指针smart pointers)。智能指针通常重载指针解引用运算符(operator->operator*),但在Item20中解释看std::weak_ptr是个例外。

在源代码注释中,我有时将“constructor”(构造函数)缩写为ctor,将“destructor”(析构函数)缩写为dtor。(译者注:但译文中基本都完整翻译了而没使用缩写。)

报告bug,提出改进意见

我尽力将本书写的清晰、准确、富含有用的信息,但是当然还有些去做得更好的办法。如果你找到了任何类型的错误(技术上的,叙述上的,语法上的,印刷上的等),或者有些建议如何改进本书,请给我发电子邮件到emc++@aristeia.com。新的印刷给了我改进《Modern Effective C++》的机会,但我也不能解决我不知道的问题!

diff --git a/print.html b/print.html index 5fb8f22..1799419 100644 --- a/print.html +++ b/print.html @@ -201,7 +201,7 @@ someFunc(std::move(wid)); //在这个someFunc调用中,w是通过移动 //创建的副本

右值副本通常由移动构造产生,左值副本通常由拷贝构造产生。如果你仅仅知道一个对象是其他对象的副本,构造这个副本需要花费多大代价是没法说的。比如在上面的代码中,在不知道是用左值还是右值传给someFunc情况下,没法说来创建形参w花费代价有多大。(你必须还要知道移动和拷贝Widget的代价。)

-

在函数调用中,调用地传入的表达式称为函数的实参argument)。实参被用来初始化函数的形参parameter)。在上面第一次调用someFunc中,实参为wid。在第二次调用中,实参是std::move(wid)。两个调用中,形参都是w。实参和形参的区别非常重要,因为形参是左值,而用来初始化形参的实参可能是左值或者右值。这一点尤其与完美转发perfect forwarding)过程有关,被传给函数的实参以原实参的右值性(rvalueness)或左值性(lvalueness),再被传给第二个函数。(完美转发讨论细节在Item30。)

+

在函数调用中,调用地传入的表达式称为函数的实参argument)。实参被用来初始化函数的形参parameter)。在上面第一次调用someFunc中,实参为wid。在第二次调用中,实参是std::move(wid)。两个调用中,形参都是w。实参和形参的区别非常重要,因为形参是左值,而用来初始化形参的实参可能是左值或者右值。这一点尤其与完美转发perfect forwarding)过程有关,被传给函数的实参以原实参的右值性(rvalueness)或左值性(lvalueness),再被传给第二个函数。(完美转发讨论细节在Item30。)

设计优良的函数是异常安全exception safe)的,意味着他们至少提供基本的异常安全保证(即基本保证basic guarantee)。这样的函数保证调用者在异常抛出时,程序不变量保持完整(即没有数据结构是毁坏的),且没有资源泄漏。有强异常安全保证的函数确保调用者在异常产生时,程序保持在调用前的状态。

当我提到“函数对象”时,我通常指的是某个支持operator()成员函数的类型的对象。换句话说,这个对象的行为像函数一样。偶尔我用稍微更普遍一些的术语,表示可以用非成员函数语法调用的任何东西(即“fuctionName(arguments)”)。这个广泛定义包括的不仅有支持operator()的对象,还有函数和类似C的函数指针。(较窄的定义来自于C++98,广泛点的定义来自于C++11。)将成员函数指针加进来的更深的普遍化产生了我们所知的可调用对象callable objects)。你通常可以忽略其中的微小区别,简单地认为函数对象和可调用对象为C++中可以用函数调用语法调用的东西。

通过lambda表达式创建的函数对象称为闭包closures)。没什么必要去区别lambda表达式和它们创建的闭包,所以我经常把它们统称lambdas。类似地,我几乎不区分函数模板function templates)(即产生函数的模板)和模板函数template functions)(即从函数模板产生的函数)。类模板class templates)和模板类template classes)同上。

@@ -228,10 +228,10 @@ enum class Color { Yellow, Red, Blue }; //限域enum定义

定义也有资格称为声明,所以我倾向于只有声明,除非这个东西有个定义非常重要。

-

我定义一个函数的签名signature)为它声明的一部分,这个声明指定了形参类型和返回类型。函数名和形参名不是签名的一部分。在上面的例子中,func的签名是bool(const Widget&)。函数声明中除了形参类型和返回类型之外的元素(比如noexcept或者constexpr,如果存在的话)都被排除在外。(noexceptconstexprItem1415叙述。)“签名”的官方定义和我的有点不一样,但是对本书来说,我的定义更有用。(官方定义有时排除返回类型。)

+

我定义一个函数的签名signature)为它声明的一部分,这个声明指定了形参类型和返回类型。函数名和形参名不是签名的一部分。在上面的例子中,func的签名是bool(const Widget&)。函数声明中除了形参类型和返回类型之外的元素(比如noexcept或者constexpr,如果存在的话)都被排除在外。(noexceptconstexprItem1415叙述。)“签名”的官方定义和我的有点不一样,但是对本书来说,我的定义更有用。(官方定义有时排除返回类型。)

新的C++标准保持了旧标准写的代码的有效性,但是偶尔标准化委员会废弃deprecate)一些特性。这些特性在标准化的“死囚区”中,可能在未来的标准中被移除。编译器可能警告也可能不警告这些废弃特性的使用,但是你应当尽量避免使用它们。它们不仅可能导致将来对移植的头痛,也通常不如来替代它们的新特性。例如,std::auto_ptr在C++11中被废弃,因为std::unique_ptr可以做同样的工作,而且只会做的更好。

有时标准说一个操作的结果有未定义的行为undefined behavior)。这意味着运行时表现是不可预测的,不用说你也想避开这种不确定性。有未定义行为的行动的例子是,在std::vector范围外使用方括号(“[]”),解引用未初始化的迭代器,或者引入数据竞争(即有两个或以上线程,至少一个是writer,同时访问相同的内存位置)。

-

我将那些比如从new返回的内置指针(build-in pointers)称为原始指针raw pointers)。原始指针的“反义词”是智能指针smart pointers)。智能指针通常重载指针解引用运算符(operator->operator*),但在Item20中解释看std::weak_ptr是个例外。

+

我将那些比如从new返回的内置指针(build-in pointers)称为原始指针raw pointers)。原始指针的“反义词”是智能指针smart pointers)。智能指针通常重载指针解引用运算符(operator->operator*),但在Item20中解释看std::weak_ptr是个例外。

在源代码注释中,我有时将“constructor”(构造函数)缩写为ctor,将“destructor”(析构函数)缩写为dtor。(译者注:但译文中基本都完整翻译了而没使用缩写。)

报告bug,提出改进意见

我尽力将本书写的清晰、准确、富含有用的信息,但是当然还有些去做得更好的办法。如果你找到了任何类型的错误(技术上的,叙述上的,语法上的,印刷上的等),或者有些建议如何改进本书,请给我发电子邮件到emc++@aristeia.com。新的印刷给了我改进《Modern Effective C++》的机会,但我也不能解决我不知道的问题!

@@ -3238,7 +3238,7 @@ w1 = std::move(w2); //移动赋值w1

在本章的这些小节中,非常重要的一点是要牢记形参永远是左值,即使它的类型是一个右值引用。比如,假设

void f(Widget&& w);
 
-

形参w是一个左值,即使它的类型是一个rvalue-reference-to-Widget。(如果这里震惊到你了,请重新回顾从本书简介开始的关于左值和右值的总览。)

+

形参w是一个左值,即使它的类型是一个rvalue-reference-to-Widget。(如果这里震惊到你了,请重新回顾从本书简介开始的关于左值和右值的总览。)

条款二十三:理解std::movestd::forward

Item 23: Understand std::move and std::forward

为了了解std::movestd::forward,一种有用的方式是从它们不做什么这个角度来了解它们。std::move不移动(move)任何东西,std::forward也不转发(forward)任何东西。在运行时,它们不做任何事情。它们不产生任何可执行代码,一字节也没有。