Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ “什么是”呢;*this";的右值引用;?_C++_C++11_Move Semantics_C++ Faq_Qualifiers - Fatal编程技术网

C++ “什么是”呢;*this";的右值引用;?

C++ “什么是”呢;*this";的右值引用;?,c++,c++11,move-semantics,c++-faq,qualifiers,C++,C++11,Move Semantics,C++ Faq,Qualifiers,在clang的建议中,我遇到了一个名为“此项的右值参考”的建议 我已经读了很多关于右值引用的书并理解了它们,但我不认为我知道这一点。我在网上也找不到太多使用这些术语的资源 页面上有一个到提案文件的链接:(将移动语义扩展到*this),但我也没有从中得到太多的例子 这个功能是关于什么的 假设一个类上有两个函数,它们都具有相同的名称和签名。但其中一个被声明为const: void SomeFunc() const; void SomeFunc(); 如果类实例不是常量,重载解析将优先选择非常量版本

在clang的建议中,我遇到了一个名为“此项的右值参考”的建议

我已经读了很多关于右值引用的书并理解了它们,但我不认为我知道这一点。我在网上也找不到太多使用这些术语的资源

页面上有一个到提案文件的链接:(将移动语义扩展到*this),但我也没有从中得到太多的例子


这个功能是关于什么的

假设一个类上有两个函数,它们都具有相同的名称和签名。但其中一个被声明为
const

void SomeFunc() const;
void SomeFunc();
如果类实例不是常量,重载解析将优先选择非常量版本。如果实例是
const
,则用户只能调用
const
版本。而
this
指针是
const
指针,因此无法更改实例

此`的“r值参考”允许您添加另一个备选方案:

void RValueFunc() &&;
这允许您拥有一个只能在用户通过适当的r值调用时才能调用的函数。因此,如果该函数位于类型
对象中

Object foo;
foo.RValueFunc(); //error: no `RValueFunc` version exists that takes `this` as l-value.
Object().RValueFunc(); //calls the non-const, && version.
通过这种方式,您可以根据对象是否通过r值进行访问来专门化行为

请注意,不允许在r值参考版本和非参考版本之间重载。也就是说,如果您有成员函数名,则其所有版本要么使用此上的l/r值限定符,要么都不使用。您不能这样做:

void SomeFunc();
void SomeFunc() &&;
void SomeFunc() &;
void SomeFunc() &&;
您必须这样做:

void SomeFunc();
void SomeFunc() &&;
void SomeFunc() &;
void SomeFunc() &&;
请注意,此声明更改了
*此
的类型。这意味着
和&
版本将所有访问成员都作为r值引用。因此,可以轻松地从对象内部移动。建议的第一个版本中给出的示例为(注意:对于C++11的最终版本,以下内容可能不正确;它直接来自最初的“来自此方案的r值”):

X类{
std::矢量数据;
公众:
// ...
std::vector const&data()const&{return data}
std::vector&&data()&&{返回数据}
};
xf();
// ...
X;
std::vector a=x.data();//复制
std::vector b=f().data();//移动
首先,“ref-qualifiers for*this”只是一个“营销声明”。该
*this
的类型永远不会改变,请参阅本文底部。不过,使用此措辞更容易理解

接下来,以下代码根据函数†“隐式对象参数”的ref限定符选择要调用的函数:

当调用函数的对象是一个右值(例如,未命名的临时对象)时,整个过程允许您利用这一事实

struct test2{
  std::unique_ptr<int[]> heavy_resource;

  test2()
    : heavy_resource(new int[500]) {}

  operator std::unique_ptr<int[]>() const&{
    // lvalue object, deep copy
    std::unique_ptr<int[]> p(new int[500]);
    for(int i=0; i < 500; ++i)
      p[i] = heavy_resource[i];

    return p;
  }

  operator std::unique_ptr<int[]>() &&{
    // rvalue object
    // we are garbage anyways, just move resource
    return std::move(heavy_resource);
  }
};
您肯定希望下面的函数调用free函数,不是吗

char const* s = "free foo!\n";
foo f;
f << s;
然后,包含隐含对象参数的参数列表将与重载集中包含的每个函数的参数列表相匹配。在本例中,参数列表将仅包含该对象参数。让我们看看它是什么样子:

// first call to 'f' in 'main'
test t;
f1(t); // 't' (lvalue) can match 'test&' (lvalue reference)
       // kept in overload-set
f2(t); // 't' not an rvalue, can't match 'test&&' (rvalue reference)
       // taken out of overload-set
如果在测试集合中的所有重载后,只剩下一个重载,则重载解析成功,并调用链接到该转换重载的函数。对“f”的第二次调用也是如此:

// second call to 'f' in 'main'
f1(test()); // 'test()' not an lvalue, can't match 'test&' (lvalue reference)
            // taken out of overload-set
f2(test()); // 'test()' (rvalue) can match 'test&&' (rvalue reference)
            // kept in overload-set
但是请注意,如果我们没有提供任何ref限定符(因此没有重载函数),
f1
将匹配一个右值(仍然
§13.3.1
):

p5[…]对于未声明ref限定符的非静态成员函数,另一条规则适用:

  • 即使隐式对象参数不是限定的
    const
    ,只要在所有其他方面参数可以转换为隐式对象参数的类型,就可以将右值绑定到参数
struct测试{

void f(){std::cout对于左值ref限定符表单还有一个额外的用例。C++98的语言允许为属于右值的类实例调用非
const
成员函数。这导致了与右值的概念背道而驰的各种奇怪,并偏离了内置类型的工作方式:

struct S {
  S& operator ++(); 
  S* operator &(); 
};
S() = S();      // rvalue as a left-hand-side of assignment!
S& foo = ++S(); // oops, dangling reference
&S();           // taking address of rvalue...
左值引用限定符解决了以下问题:

struct S {
  S& operator ++() &;
  S* operator &() &;
  const S& operator =(const S&) &;
};

现在操作符的工作方式与内置类型类似,只接受左值。

我认为您需要
std::move
第二个版本,非?还有,为什么右值引用返回?@Xeo:因为这就是提案中的示例;我不知道它是否仍然适用于当前版本。以及r值引用的原因e return是因为移动应该由捕获它的人决定。它还不应该发生,以防他真的想将它存储在一个&&而不是一个值中。对,我想了一下我第二个问题的原因。我想知道,对临时成员的右值引用是否会延长该临时成员的寿命,或者m余烬?我可以发誓我不久前在电视上看到了一个关于这个的问题…@Xeo:这不完全是真的。重载解析总是会选择非常量版本,如果它存在的话。你需要做一个转换来获得常量版本。我更新了帖子来澄清。我想我可以解释一下,毕竟我为C++11创建了这个功能;)Xeo坚持认为它不会更改
*this
的类型是正确的,但是我可以理解混淆的原因。这是因为ref限定符更改了隐式(或“隐藏”)函数参数的类型,“this”(此处特意引用!)对象在重载解析和函数调用期间被绑定。因此,
*this
没有更改,因为正如Xeo所解释的,这是固定的。相反,更改“hidden”参数使其成为左值或右值引用,就像
const
函数限定符使其成为
const
等。我相信parameter类型正确
// second call to 'f' in 'main'
f1(test()); // 'test()' not an lvalue, can't match 'test&' (lvalue reference)
            // taken out of overload-set
f2(test()); // 'test()' (rvalue) can match 'test&&' (rvalue reference)
            // kept in overload-set
struct test{
  void f() { std::cout << "lvalue or rvalue object\n"; }
};

int main(){
  test t;
  t.f(); // OK
  test().f(); // OK too
}
struct S {
  S& operator ++(); 
  S* operator &(); 
};
S() = S();      // rvalue as a left-hand-side of assignment!
S& foo = ++S(); // oops, dangling reference
&S();           // taking address of rvalue...
struct S {
  S& operator ++() &;
  S* operator &() &;
  const S& operator =(const S&) &;
};