[英]Member function reference qualified return type
读迈耶斯的新书,我发现与此非常相似:
// compile with
// g++-4.8 --std=c++11 -Wall main3.cc && ./a.out
#include <iostream>
#include <vector>
class Widget
{
public:
using DType = std::vector<int>;
DType& data() & // lvalue
{
std::cout << "data (lvalue) : " << &data_[0] << std::endl;
return data_;
};
DType data() && // rvalue
{
std::cout << "data (rvalue) : " << &data_[0] << std::endl;
return std::move(data_);
};
// Please Note
// int parameter is here to make the overloading possible
// in a single class
DType&& data(int) &&
{
std::cout << "data (rvalue ref): " << &data_[0] << std::endl;
return std::move(data_);
};
private:
DType data_ { 0 };
};
Widget getWidget() { return Widget(); }
int main(int argc, char *argv[])
{
Widget w1;
std::vector<int> d1 = w1.data();
std::cout << "d1 copied : " << &d1[0] << std::endl;
std::vector<int> d2 = getWidget().data();
std::cout << "d2 moved : " << &d2[0] << std::endl;
std::vector<int> d3 = getWidget().data(0);
std::cout << "d3 moved : " << &d3[0] << std::endl;
return 0;
}
我的意思很简单:我希望能在盒子上得到这些结果
data (lvalue) : 0x8e28008
d1 copied : 0x8e28018
data (rvalue) : 0x8e28028
d2 moved : 0x8e28028
data (rvalue ref): 0x8e28038
d3 moved : 0x8e28038
因此,在复制第二个和第三个向量的同时复制了第一个向量。
您可以使用两种不同的签名来实现移动操作:
一个返回右值
DType data() && // rvalue
和一个重现右值引用
DType&& data() &&
他们达到了相同的结果:我看不到任何区别吗? 什么是“最好”的?
您可以使用两种不同的签名来实现移动操作:
那是错的。
第一个签名(返回DType
)执行到返回值的移动。 第二个签名,一个返回DType&&
签名,仅返回一个引用。 它什么也没动。
此移动发生在其他代码中,特别是std::vector<int> d3 =
。 从xvalue初始化向量将执行移动。 那就是移动的方向,而不是功能。 但是 ,其他类型的操作不会执行以下操作:
// no move, just binding the member to a reference
std::vector<int>&& d3 = getWidget().data(0);
但是,使用第一个函数,总是会发生移动:
// move into a temporary, and bind *that* to a reference
std::vector<int>&& d2 = getWidget().data();
第二个签名很危险。 意外地将引用返回给它很容易。 在您认为某些内容已移出但没有移出的地方,很容易编写误导性的客户端代码。 有一个明智的用例返回右值引用,该用例已经由标准库以std::move
和std::forward
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.