作者回复: 简单来说,在对本地变量进行返回时,不用 std::move。实际上,我在第 3 讲就写了:
“有一种常见的 C++ 编程错误,是在函数里返回一个本地对象的引用。由于在函数结束时本地对象即被销毁,返回一个指向本地对象的引用属于未定义行为。理论上来说,程序出任何奇怪的行为都是正常的。
“在 C++11 之前,返回一个本地对象意味着这个对象会被拷贝,除非编译器发现可以做返回值优化(named return value optimization,或 NRVO),能把对象直接构造到调用者的栈上。从 C++11 开始,返回值优化仍可以发生,但在没有返回值优化的情况下,编译器将试图把本地对象移动出去,而不是拷贝出去。这一行为不需要程序员手工用 `std::move` 进行干预——使用`std::move` 对于移动行为没有帮助,反而会影响返回值优化。”
作者回复: 用默认构造函数代表空,或者用 optional<对象> (不构造)代表空,或者抛异常代表不正常(视是否不正常而定)。
optional 会在第 22 讲里讨论。
作者回复: 看这个页面吧:
https://en.cppreference.com/w/cpp/compiler_support
目前 GCC 领先一些(可以用 -std=c++2a 启用 20 的功能),但还没有哪家完整支持 C++20。
作者回复: 多谢。已修正。
作者回复: 没有启用 C++17 标准吧?
应该是上面这种情况。不是的话,请描述具体的编译器版本和编译的命令行参数。
作者回复: 如果都是返回而非修改的话,可以使用 pair、tuple、tie 和第 8 讲讨论的结构化绑定。
作者回复: 你这不就是我下面给出的 getA_named 吗?确实不会拷贝啊,我这一讲就是这么写的。就是让你看到,返回值优化在这儿起的作用。
作者回复: 好问题。利用第 14 讲的 SFINAE 技巧,是可以写出来的。比如,你希望检测是不是有下面第一个重载:
class Obj {
public:
void foo() &&;
void foo() const &;
};
可以定义下面这样的 type trait:
template <typename T, typename = void_t<>>
struct has_rvalue_ref_foo : false_type {};
template <typename T>
struct has_rvalue_ref_foo<
T, void_t<decltype(static_cast<void (T::*)() &&>(&T::foo))>>
: true_type {};
上面第一个 foo 的重载在的话,使用 has_rvalue_ref_foo<Obj>::value 就能得到编译期常量 true。
作者回复: 先试试升级环境、充分测试看看有没有问题。也许没问题呢?
作者回复: 对于功能和版本的关系,这个页面比较全:
https://en.cppreference.com/w/cpp/compiler_support
作者回复: C++编译器哪会做这么不必要的事……就是一次移动。如果有返回值优化的话,一次移动都不会有。
作者回复: 对,是调用移动构造变成调用拷贝构造,如果原来就直接返回值优化掉了,那不会变化。
作者回复: VS 2017 下也能过的。你没有按环境要求里说的加上 /std:c++17。了解细节,可以看参考资料 [3]。