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

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

  •  36
  • alfC  · 技术社区  · 10 年前

    为了使这段带有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.4 gcc 4.8.3 .


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

    1. std::move(*this) 语法和概念正确

    2. 然而,如果 gun 不是所需接口的一部分,没有理由重载它的lv-ref和rv-ref版本。两个具有不同名称的函数可以执行相同的任务。毕竟,ref限定符在接口级别很重要,通常只是公共部分。

    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)`.
    };
    

    但是,如果 是(通用)接口的一部分 std::move(*this) 是必要的,但只有在那时。而且,即使 不是接口的一部分,不拆分函数具有可读性优势 作为两个不同命名的函数,其成本是。。。, std::move(*this) .

    编辑2 :回想起来,这与C++98的情况类似 const 而不是- 常量 相同功能的过载。在里面 某些情况下 使用它是有意义的 const_cast (另一种形式的强制转换)不重复代码并具有同名的两个函数( https://stackoverflow.com/a/124209/225186 ). …尽管在更复杂的情况下,有辅助的私有函数为接口函数委派正确的行为是有意义的。

    1 回复  |  直到 4 年前
        1
  •  24
  •   user743382 user743382    9 年前

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

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

    制作 *这个 右值将表明 fun 的第一次呼叫 gun 可能会使对象不可用。第二次调用将失败,可能会严重失败。这不是应该含蓄地发生的事情。

    这也是为什么在里面 void f(T&& t) , t 是左值。在这方面, *这个 与任何参考函数参数没有区别。