std :: move(* this)是一个好模式吗?

时间:2014-08-15 21:48:14

标签: c++ c++11 this move-semantics lvalue

为了使这段代码与C ++ 11引用限定符按预期工作,我必须引入一个听起来不正确的std::move(*this)

#include<iostream>
struct A{
    void gun() const&{std::cout << "gun const&" << std::endl;}
    void gun() &&{std::cout << "gun&&" << std::endl;}
    void fun() const&{gun();}
    void fun() &&{std::move(*this).gun();} // <-- is this correct? or is there a better option
};

int main(){
    A a; a.fun(); // prints gun const&
    A().fun(); // prints gun&&
}

有些事情听起来不对。 std::move是否必要?这是推荐使用吗?目前如果我不使用它,我会在两种情况下得到gun const&,这不是预期的结果。

(似乎*this是隐式的,左值引用总是有意义,但这是逃避使用move的唯一方法)

使用clang 3.4gcc 4.8.3进行测试。

编辑:这是我从@hvd回答中了解到的:

1)std::move(*this)在语法和概念上都是正确的

2)但是,如果gun不是所需接口的一部分,则没有理由重载它的lv-ref和rv-ref版本。两个具有不同名称的函数可以完成相同的工作。在所有ref-qualifiers在接口级别(通常只是公共部分)之后很重要。

struct A{
    private:
    void gun() const{std::cout << "gun const&" << std::endl;}
    void gun_rv(){std::cout << "gun called from fun&&" << std::endl;}
    public:
    void fun() const&{gun();}
    void fun() &&{gun_rv();} // no need for `std::move(*this)`.
};

但同样,如果gun是(通用)接口的一部分,那么std::move(*this)是必要的,但只有这样。而且,即使gun不是界面的一部分,在不将功能gun拆分为两个不同命名的函数时也具有可读性优势,而且成本也很好...... {{1} }。

EDIT 2 :回想起来,这类似于同一函数的std::move(*this)和无 - const重载的C ++ 98案例。在某些情况中,使用const(另一种形式的强制转换)来重复代码并使两个函数具有相同的名称是有意义的... 编辑3 :... https://stackoverflow.com/a/124209/225186

1 个答案:

答案 0 :(得分:19)

是的,*this始终是左值,无论如何调用成员函数,因此如果您希望编译器将其视为右值,则需要使用std::move或等效函数。它必须是,考虑到这个类:

struct A {
  void gun() &; // leaves object usable
  void gun() &&; // makes object unusable

  void fun() && {
    gun();
    gun();
  }
};

*this设为左值会表明fun第一次调用gun会导致对象无法使用。然后第二次调用会失败,可能很糟糕。这不是隐含的事情。

这就是为什么void f(T&& t)t是左值的原因。在这方面,*this与任何参考函数参数没有区别。