【问题标题】:How to apply move semantics while inheriting from template class如何在从模板类继承时应用移动语义
【发布时间】:2017-10-26 23:57:33
【问题描述】:

当我运行下面的代码时,它会产生以下输出, 第一部分直接使用模板, 第二个使用从模板派生的类。 派生类中不调用移动语义(以粗体显示)

模板假人:初始化构造函数
模板假人:初始化构造函数
模板虚拟:空构造函数
模板虚拟:空构造函数
模板虚拟:+ 运算符
模板虚拟:移动赋值
2

模板假人:初始化构造函数
模板假人:初始化构造函数
模板虚拟:空构造函数
模板虚拟:空构造函数
模板虚拟:+ 运算符
模板虚拟:复制构造函数
模板虚拟:复制赋值
2

我认为原因很明确 - 命名参数会将参数转换为左值,因此模板接收左值并调用复制构造函数。

问题是在这种情况下如何强制移动语义?

  #include <iostream>

  using namespace std;

  template <typename T> class Dummy {

  public:

    T val;

    Dummy& operator=(const Dummy& d){
      val = d.val;
      cout << "Template Dummy: copy assignment\n" ;
      return *this;
    }

    Dummy operator+(const Dummy &d) {
      Dummy res;
      res.val = val + d.val;
      cout << "Template Dummy: +  operator\n" ;
      return res;
    }

    // constructors
    Dummy() {
      val = 0;
      cout << "Template Dummy: empty constructor\n" ;
    }

    Dummy(const T v) {
      val = v;
      cout << "Template Dummy: initializing constructor\n" ;
    }

    Dummy(const Dummy &d) {
      val = d.val;
      cout << "Template Dummy: copy constructor\n" ;
    }

    // move semantics
    Dummy(const Dummy&& d) {
      val = d.val;
      cout << "Template Dummy: move constructor\n" ;
    }

    Dummy& operator=(const Dummy&& d){
      val = d.val;
      cout << "Template Dummy: move assignment\n" ;
      return *this;
    }
  };

  class FloatDummy : public Dummy<float> {
  public:

      FloatDummy& operator=(const FloatDummy& d){
        Dummy<float>::operator=(d);
        return *this;
      }

      FloatDummy operator+(const FloatDummy &d) {
        return (FloatDummy) Dummy<float>::operator+(d);
      }

      // constructors
      FloatDummy() : Dummy<float>() {};
      FloatDummy(float v) : Dummy<float>(v) {}
      FloatDummy(const FloatDummy &d) : Dummy<float>(d) {}
      FloatDummy(const Dummy<float> &d) : Dummy<float>(d) {}

      // move semantics
      FloatDummy(const FloatDummy&& d) : Dummy<float>(d) {}

      FloatDummy& operator=(const FloatDummy&& d){

      // here d is already an lvalue because it was named
      // thus the template invokes a copy assignment    
      Dummy<float>::operator=(d);
      return *this;
    }
  };

  int main() {
    Dummy<float> a(1), b(1);
    Dummy<float> c;
    c = a + b;
    cout << c.val << '\n';;

    FloatDummy d(1), e(1);
    FloatDummy f;
    f = d + e;
    cout << f.val << '\n';
  }

【问题讨论】:

  • const &amp;&amp;的所有情况中删除const,并使用std::move(d)d移动

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


【解决方案1】:

您不能从const&amp; 移动。要修复,只需从所有移动操作中删除 const

FloatDummy(FloatDummy&& d) : Dummy<float>(d) {}
//         ^^^^^^^^^^^^ no longer FloatDummy const&&

FloatDummy& operator=(FloatDummy&& d) { /*...*/ }
//                    ^^^^^^^^^^^^ ditto

迁移的本质是取得资源的所有权,如果你不能修改你的源,你怎么能取得一些东西的所有权呢?因此,默认情况下,移动操作不适用于const 类型。

您需要对 Dummy 类执行相同的操作。


您需要调用std::move()d 转换为右值引用:尽管d 的参数类型是右值引用,但在函数本身内部d 几乎被视为左值引用。这意味着当您将它传递给实际使用它的任何东西时,您仍然需要将其转换为右值引用(std::move() 的全部内容)。

在你的情况下,当你将它传递给Dummy&lt;float&gt;的构造函数或Dummy&lt;float&gt;::operator=时是正确的:

FloatDummy(FloatDummy&& d) : Dummy<float>(std::move(d)) {}
//                                        ^^^^^^^^^ calling std::move()
//                                                  otherwise copy ctor overload is chosen

FloatDummy& operator=(FloatDummy&& d)
{
    Dummy<float>::operator=(std::move(d));
    //                      ^^^^^^^^^ ditto
    return *this;
}

【讨论】:

  • 这样就解决了问题。我还缺少一个未从模板复制的移动构造函数,导致复制。现在我有一个 move 构造函数和一个 move 赋值。谢谢!!
猜你喜欢
  • 1970-01-01
  • 2018-05-23
  • 1970-01-01
  • 2018-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多