• 小一日一
    2019-12-18
    我认为老师应该讲一下NRVO/RVO与std::move()的区别,这个问题曾经困扰过我,从stackoverflow的问题来看,学习c++11时大多数人都思考过这个问题:https://stackoverflow.com/questions/4986673/c11-rvalues-and-move-semantics-confusion-return-statement

    作者回复: 简单来说,在对本地变量进行返回时,不用 std::move。实际上,我在第 3 讲就写了:

    “有一种常见的 C++ 编程错误,是在函数里返回一个本地对象的引用。由于在函数结束时本地对象即被销毁,返回一个指向本地对象的引用属于未定义行为。理论上来说,程序出任何奇怪的行为都是正常的。

    “在 C++11 之前,返回一个本地对象意味着这个对象会被拷贝,除非编译器发现可以做返回值优化(named return value optimization,或 NRVO),能把对象直接构造到调用者的栈上。从 C++11 开始,返回值优化仍可以发生,但在没有返回值优化的情况下,编译器将试图把本地对象移动出去,而不是拷贝出去。这一行为不需要程序员手工用 `std::move` 进行干预——使用`std::move` 对于移动行为没有帮助,反而会影响返回值优化。”

     2
     8
  • 木瓜777
    2019-12-18
    项目中一直使用您说的老方法,目前看编译器有优化的话,后面会逐步考虑采用返回对象的方法! 有个问题问下,如果要返回空对象,该如何做? 是直接采用空的构造函数?

    作者回复: 用默认构造函数代表空,或者用 optional<对象> (不构造)代表空,或者抛异常代表不正常(视是否不正常而定)。

    optional 会在第 22 讲里讨论。

    
     4
  • hello world
    2019-12-18
    请问老师这个C++20什么时候发布编译器之类的啊?还是说已经有了?

    作者回复: 看这个页面吧:

    https://en.cppreference.com/w/cpp/compiler_support

    目前 GCC 领先一些(可以用 -std=c++2a 启用 20 的功能),但还没有哪家完整支持 C++20。

     2
     2
  • nelson
    2019-12-19
    文稿中的代码片段
    ec = multiply(&temp, a, b);
    if (result != SUCCESS)
    {
      goto end;
    }

    result 应该是 ec吧
    展开

    作者回复: 多谢。已修正。

    
     1
  • 风清扬
    2020-02-09
    关于返回值优化的实验我们就做到这里。下一步,我们试验一下把移动构造函数删除:
    A(A&&)=delete 我们可以立即看到“Copy A”出现在了结果输出中,说明目前结果变成拷贝构造了。

    这里我修改成A(A&&) = delete后,编译报错:提示:error: use of deleted function ‘A::A(A&&)

    作者回复: 没有启用 C++17 标准吧?

    应该是上面这种情况。不是的话,请描述具体的编译器版本和编译的命令行参数。

     2
    
  • 空气
    2020-01-04
    我在工作中使用引用出参的场景之一是同时返回多个对象,如果使用返回值就要封装很多不同结构体。请问老师这种场景建议怎么实现?

    作者回复: 如果都是返回而非修改的话,可以使用 pair、tuple、tie 和第 8 讲讨论的结构化绑定。

    
    
  • 传说中的成大大
    2020-01-04
    #include <iostream>
      2 using namespace std;
      3 // Can copy and move
      4 class A {
      5 public:
      6 A() {
      7 cout << "Create A\n";
      8 }
      9 ~A() {
     10 cout << "Destroy A\n";
     11 }
     12 A(const A&) {
     13 cout << "Copy A\n";
     14 }
     15 A(A&&) { cout << "Move A\n"; }
     16 };
     17 A getA_unnamed(){
     18 // return A();
     19 A a;
     20 return a;
     21 }
     22 int main(){
     23 auto a = getA_unnamed();
     24 }
    g++ main.cpp
    ./a.out 也不会执行copy操作呢?我的操作系统是ubuntu
    展开

    作者回复: 你这不就是我下面给出的 getA_named 吗?确实不会拷贝啊,我这一讲就是这么写的。就是让你看到,返回值优化在这儿起的作用。

    
    
  • 小白兔纸白又白
    2019-12-31
    请问有何方法可以测试编译器是否为一个类提供了右值引用的版本的成员函数

    作者回复: 好问题。利用第 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。

    
    
  • petit_kayak
    2019-12-24
    一直使用共享指针,非常喜欢这些新的优化,能简化非常多代码,但现实是需要考虑很多无法升级的旧环境,不能随便使用c++11及以后的写法

    作者回复: 先试试升级环境、充分测试看看有没有问题。也许没问题呢?

    
    
  • 光城~兴
    2019-12-22
    加入了move assignment后,默认是调用move assignment而不是copy assignment。
    
    
  • 光城~兴
    2019-12-22
    您好,老师,我想问一下c++xx与gcc版本的对应关系,还有这节提到的返回值优化在c++17中的结果与c++14及之前的结果(禁用返回值优化,编译后的结果)是不一样的,像这种有没有参考资料呢?

    作者回复: 对于功能和版本的关系,这个页面比较全:

    https://en.cppreference.com/w/cpp/compiler_support

    
    
  • 花晨少年
    2019-12-21
    我们继续变形一下:
    #include <stdlib.h>
    A getA_duang()
    {
      A a1;
      A a2;
      if (rand() > 42) {
        return a1;
      } else {
        return a2;
      }
    }
    int main()
    {
      auto a = getA_duang();
    }
    这回所有的编译器都被难倒了,输出是:
    Create A
    Create A
    Move A
    Destroy A
    Destroy A
    Destroy A

    ———————
    老师这个结果应该还是会有优化在的吧?如果完全没有优化应该是两个移动才对,a1或者a2移动给返回值是一次,返回值移动给a又是一次,如果真是这样,哪次被优化掉了?第二次吗
    展开

    作者回复: C++编译器哪会做这么不必要的事……就是一次移动。如果有返回值优化的话,一次移动都不会有。

     3
    
  • 花晨少年
    2019-12-21
    关于返回值优化的实验我们就做到这里。下一步,我们试验一下把移动构造函数删除:
      A(A&&) = delete;
    我们可以立即看到“Copy A”出现在了结果输出中,说明目前结果变成拷贝构造了
    ————————————————————————
    请问这种情况说的是针对getA_duang()函数吧?不包括 getA_named() 等函数吧

    作者回复: 对,是调用移动构造变成调用拷贝构造,如果原来就直接返回值优化掉了,那不会变化。

    
    
  • 西钾钾
    2019-12-20
    以下的代码中,无论是将拷贝构造函数还是移动构造函数置为delete,都不能正常编译(vs2017)。为啥只是使用一次构造函数,老师能简单讲下这个原理么?
    #include <iostream>

    using namespace std;

    // Can copy and move
    class A {
    public:
      A() { cout << "Create A\n"; }
      ~A() { cout << "Destroy A\n"; }
      A(const A&) { cout << "Copy A\n"; }
      A(A&&) { cout << "Move A\n"; }
    };

    A getA_unnamed()
    {
      return A();
    }

    int main()
    {
      auto a = getA_unnamed();
    }
    展开

    作者回复: VS 2017 下也能过的。你没有按环境要求里说的加上 /std:c++17。了解细节,可以看参考资料 [3]。

    
    
我们在线,来聊聊吧