【问题标题】:Moving members of class passed as a const reference argument移动类的成员作为 const 引用参数传递
【发布时间】:2020-09-14 18:28:26
【问题描述】:

考虑:

template <typename... Args>
ResourceHolder& operator+=(const ResourceInserter<Key, Args...>& inserter) {

    if constexpr (sizeof...(Args) == 0) {
        insert(std::move(inserter.key),
               std::move(inserter.fileName));
    } else {
        insert(std::move(inserter.key),
               std::move(inserter.fileName),
               std::move(std::get<Args...>(inserter.tuple)));
    }

    return *this;
}

你认为这是移动语义的正确用法吗?

ResourceInserterinserter 实例作为 const 引用传递。

【问题讨论】:

  • 移动 const 对象一般是简单的复制。

标签: c++ c++11 move-semantics stdtuple


【解决方案1】:

移动 const 对象通常是一个简单的副本(除非您重载 Object(const Object&amp;&amp;)),因此您对 std::move 的使用似乎没用。

如果ResourceInserter 的成员是(非常量)引用, 您的const ResourceInserter&amp; 具有“误导性”,您的举动实际上会发生。

【讨论】:

    【解决方案2】:

    没有。

    您正在投射到const Key &amp;&amp; 等。Key::Key(const Key&amp;&amp;) 通常无法做任何有用的事情,所以您将复制。

    可能想要一对重载

    template <typename... Args>
    ResourceHolder& operator+=(const ResourceInserter<Key, Args...>& inserter) {
    
        if constexpr (sizeof...(Args) == 0) {
            insert(inserter.key,
                   inserter.fileName);
        } else {
            insert(inserter.key,
                   inserter.fileName,
                   std::get<Args...>(inserter.tuple));
        }
    
        return *this;
    }
    
    template <typename... Args>
    ResourceHolder& operator+=(ResourceInserter<Key, Args...>&& inserter) {
    
        if constexpr (sizeof...(Args) == 0) {
            insert(std::move(inserter.key),
                   std::move(inserter.fileName));
        } else {
            insert(std::move(inserter.key),
                   std::move(inserter.fileName),
                   std::move(std::get<Args...>(inserter.tuple)));
        }
    
        return *this;
    }
    

    你从右值inserter的成员移动到哪里

    【讨论】:

      【解决方案3】:

      与它的名字相反,std::move 实际上并没有移动任何东西。它只是告诉编译器尝试移动(即,通过将对象t 强制转换为右值引用类型[更具体地说,通过生成xvalue expression] 来表明它可以被“移动”)。

      但是,您的类没有接受const inserter&amp;&amp; 的构造函数,而是使用您的类的copy constructor(隐式或显式),并安全地复制。没有危险,没有陷阱。如果复制构造函数因任何原因被禁用,您将收到编译错误。

      试试这个:

      #include <iostream>
      struct Test {
         Test() { }
         Test(const Test& ) { std::cout << "COPY" << std::endl; }
         Test(Test&&)       { std::cout << "MOVE" << std::endl; }
      };
      
      int main() 
      {
          const Test t;
          Test t2 = std::move(t);
          return 0;
      }
      

      打印COPY,而不是MOVE

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多