代码之家  ›  专栏  ›  技术社区  ›  fredoverflow

什么类型的代码需要知道rvalue引用?

  •  14
  • fredoverflow  · 技术社区  · 14 年前

    我看到很多人在理解rvalue引用时遇到问题。将“普通”C++代码(例如 使用 标准库,但不实现它)需要知道新的标准出来后的R值引用,或者人/代码仅仅假装R值引用不存在吗?rvalue引用主要涉及库实现者还是所有程序员?

    8 回复  |  直到 13 年前
        1
  •  6
  •   Steve Jessop    13 年前

    在GMan(又称gmannickg)的博客文章中,我没有看到有什么不同意的地方:

    http://blackninjagames.com/?p=95

    小结:任何知道复制和交换的人(通常是三条规则的人), 应该 了解移动语义(从而了解rvalue引用),因为最佳实践习惯用法会因此而改变。因此,我认为,任何人都关心C++。

    我不认为你 要知道,因为复制和交换仍然有效,它仍然是异常安全的,等等。我想有人会争论“普通”C++代码和程序员是否需要知道复制和交换。我希望答案是“嗯,嗯,很明显”,但你永远不会知道。

    当然,可以开始使用C++0X的点会在不同的地方发生变化。在不久的将来,不学习C++ 03可能不是一个好主意。

    例如,如果可以依赖移动分配,则按值在对副本省略无效的上下文中返回大量集合将成为更好的选择。这不是C++ 03中无效的东西在C++ 0x中生效的,它的代码是 极其缓慢 在C++ 03中,你可以工作(即使只有一个好的位置) swap 在C++ 0x中变得很好,所以如果你假设R值引用不存在,你将继续在你不需要的东西上工作。如果你跳的话,它可能会干净地回到C + 03,但运行狗慢,这是一个痛苦。

    所以聪明的事可能是知道这件事, 在许多情况下假装它不存在。

        2
  •  5
  •   Jerry Coffin    14 年前

    至少在大多数情况下,你可以忽略他们,只要你觉得你想。(重新)编写标准库来使用它们允许相当大的优化和一些新的能力,但主要目标之一是现有的代码应该继续正常工作(尽管在某些情况下,更快)。

    支持现有代码意味着任何感觉到它的人都可以继续像以前一样编写代码,并且也不会受到影响(再一次,除了它们使用的某些库)可能会更快。

    同时,也有一些很好的理由 希望 至少学习一些经验法则,让他们可以简单地使用rvalue引用。一个明显的例子就是人们现在经常遇到的一个问题:他们有一个类,复制对象并没有真正意义,但是他们仍然希望能够将这些对象放在一个集合中(例如,向量)。

    他们可以通过使该类对象可移动但不可复制来做到这一点。一个最好的例子是流——现在,你不能把任何类型的IoSoW对象放入一个集合中,但是在C++ 0x中你将能够。

    另一种可能是使用“完美转发”。这样可以更容易地将以前的一些单独的函数合并为一个非常琐碎的前端,这些前端都转发给真正工作的前端。你可以一直这样做,但在某些情况下,它可以使代码相当少的重复。

        3
  •  3
  •   Peter Alexander    14 年前

    大多数人可以假装他们不存在,他们只会看到好处(在某些情况下更快的代码)。

    请记住,C++ 0x将是99.9%向后兼容的,所以所有现有代码仍然有效,这意味着您可以继续编写C++ 0x代码,就好像它是C++ 03一样。

    如果你想从rvalue引用中获益,那么你当然需要了解它们,但大多数时候这只是图书馆作者关心的问题。

        4
  •  3
  •   Kate Gregory    14 年前

    您可能不需要知道rvalue引用,也就是说,您需要编写一个函数,但是您可能会从理解move语义、了解move构造函数是什么等方面受益。如果您想使用unique_ptr(并获得性能优势,因为它没有引用计数),那么您几乎肯定需要使用std::move(比如,进入和离开一个集合),我无法想象在“如果我在这里放置一个&或一个*会怎么样?”一个典型的二年级学生处理指针的方式。

    我刚刚做了一个“VC++的新功能,C++ + 0x”在柏林的科技欧洲进行了一次关于RValk引用的幻灯片,我基本上说“你需要知道这些是因为它们使STL更快”但是我没有进一步钻研。这似乎比我在其他演讲中使用的(更长的)变体更好地被与会者接受。

        5
  •  2
  •   towi    14 年前

    我同意,那 右值引用 不是每个人都喝一杯茶--这个杯子很大。

    正因为如此,我告诉C++0X的学习者,最好的方法是开始和利用。 右值引用 是为了 使用STL并接受其设计模式 随着时间的推移。很可能你从中受益 右值引用 没有事先完全理解他们。

        6
  •  1
  •   ManicQin    14 年前

    Scott Meyers将C++0X特性划分为:

    1. 每个人的特点。
    2. 课程作者的特点。
    3. 图书馆作者的特点。

    RValues绝对是图书馆的作者。

        7
  •  1
  •   bytemaster    13 年前

    在c++11中,我会传递我计划由&存储或使用的任何内容;。这会产生最有效的代码,但会“破坏”左值兼容性,并迫使我考虑每个方法有两个(或更多)版本。不幸的是,随着参数数量的增加,rvalue和const的排列出现爆炸式增长,这使得获取函数指针变得更加“丑陋”。

    我没有提供两个(或更多)重载,一个用于左值,一个用于右值,而是决定只提供右值重载,如果用户想要传递一个左值,它们将用std::ref()、std::cref()、std::move()或我自己的helper copy()包装,这将使复制显式并将左值转换为右值。(std::ref()和std::cref()只能在参数是模板参数时工作。。。在这种情况下,该方法可能会使用std::forward<gt;()来处理移动与复制语义的自动检测。

    template<typename T>
    T copy( const T& v ) { return v; }
    

    如果我正在编写一个不“存储”或“使用”输入的方法,那么我将使用const&

    我可能应该澄清,对于任何不受益于移动语义的类型(没有深层副本),我都会使用const&方法。但是,在编写模板代码时,不希望对类型做出这种假设。

    我正在考虑的另一个做法是使某些类“仅显式复制”。

    class test  {
      public:
        test(){...};
        test( test&& t ){...}
    
      private:
        template<typename T>
        friend T copy(const T&t);
    
        test& operator=(const test&); // not implemented
        test( const test& t ){...}
    
        std::vector<char> large_data;
    };
    
    int main( int argc, char** argv ) {
      test x;
      test y = copy(x);
      test z = x; // error, test(const test&) is private...
      return 0;
    }
    

    对于任何包含“可移动成员”的类,比如字符串、向量、映射等,我都会使用这个方法。从技术上讲,我没有理由不能复制它们,但是为什么我不能尝试在任何地方移动语义,除非我真的想复制?对于隐式副本,编译器没有办法警告我正在做一些潜在的昂贵的事情。

        8
  •  0
  •   Puppy    14 年前

    如果你没有实现一个值语义类,你不需要知道。

    编辑:或完美转发。但这基本上也是图书馆的用途。