比较以下两段代码,第一段使用对大对象的引用,第二段使用大对象作为返回值.对"大对象"的强调指的是不必要地重复对象的副本是浪费的循环.
使用对大对象的引用:
void getObjData( LargeObj& a )
{
a.reset() ;
a.fillWithData() ;
}
int main()
{
LargeObj a ;
getObjData( a ) ;
}
Run Code Online (Sandbox Code Playgroud)
使用大对象作为返回值:
LargeObj getObjData()
{
LargeObj a ;
a.fillWithData() ;
return a ;
}
int main()
{
LargeObj a = getObjData() ;
}
Run Code Online (Sandbox Code Playgroud)
第一段代码不需要复制大对象.
在第二个片段中,对象是在函数内部创建的,因此通常在返回对象时需要复制.但是,在这种情况下,main()正在声明对象.编译器是否会首先创建一个默认构造的对象,然后复制返回的对象getObjData(),或者它是否与第一个片段一样有效?
我认为第二个片段更容易阅读,但我担心效率会降低.
编辑:通常,我认为案例LargeObj是通用容器类,为了参数,它们包含数千个对象.例如,
typedef std::vector<HugeObj> LargeObj ;
Run Code Online (Sandbox Code Playgroud)
所以直接修改/添加方法LargeObj不是一个可直接访问的解决方案.
可以说我们有以下代码:
std::vector<int> f()
{
std::vector<int> y;
...
return y;
}
std::vector<int> x = ...
x = f();
Run Code Online (Sandbox Code Playgroud)
看来编译器有两种方法:
(a)NRVO:Destruct x,然后构造f()代替x.
(b)移动:在temp空间中构造f(),将f()移动到x,destruct f().
根据标准,编译器是否可以自由使用这两种方法?
c++ optimization move-semantics return-value-optimization c++11
这样的签名有效的用例是什么?:
T&& foo();
Run Code Online (Sandbox Code Playgroud)
还是右值引用仅打算用作参数?
如何使用这样的功能?
T&& t = foo(); // is this a thing? And when would t get destructed?
Run Code Online (Sandbox Code Playgroud) 我有一个函数可以std::string&就地修改左值引用,返回对输入参数的引用:
std::string& transform(std::string& input)
{
// transform the input string
...
return input;
}
Run Code Online (Sandbox Code Playgroud)
我有一个辅助函数,它允许在右值引用上执行相同的内联转换:
std::string&& transform(std::string&& input)
{
return std::move(transform(input)); // calls the lvalue reference version
}
Run Code Online (Sandbox Code Playgroud)
请注意,它返回一个右值引用.
我已经阅读了关于返回右值引用的SO的几个问题(这里和这里例如),并得出结论这是不好的做法.
根据我的阅读,似乎共识是因为返回值是 rvalues,再加上考虑RVO,只需按值返回就会有效:
std::string transform(std::string&& input)
{
return transform(input); // calls the lvalue reference version
}
Run Code Online (Sandbox Code Playgroud)
但是,我还读到返回函数参数会阻止RVO优化(例如此处和此处)
这使我相信std::string&从左值参考版本transform(...)的std::string返回值到返回值会发生副本.
那是对的吗?
保留我的std::string&& transform(...)版本会更好吗?
考虑这个功能:
Thing func(){
return something;
}
Run Code Online (Sandbox Code Playgroud)
每次调用此函数时,都会生成一个副本something并传递给调用者.
我的问题是,为什么不这样做(每次我想按价值归还)?
const Thing& func(){
return something;
}
Run Code Online (Sandbox Code Playgroud)
这样,我们就没有冒充无法复制的风险something.如果客户端只需要"读取" something而不是"写入"它,那么const引用就可以完全实现.如果客户端确实需要副本,它可以简单地将const引用分配给变量,例如:
Thing thing = func(); // the object is passed by const reference, and then copied.
Run Code Online (Sandbox Code Playgroud)
那么,有没有理由简单地按价值回报?
顺便说一句,并不是因为我非常关心优化,只是因为我没有理由单纯地通过价值来回报.
跟进问题:阅读答案,我知道每种方法都有利弊.有违约吗?例如"默认按值返回"?或者它纯粹基于具体案例?
考虑以下:
struct vec
{
int v[3];
vec() : v() {};
vec(int x, int y, int z) : v{x,y,z} {};
vec(const vec& that) = default;
vec& operator=(const vec& that) = default;
~vec() = default;
vec& operator+=(const vec& that)
{
v[0] += that.v[0];
v[1] += that.v[1];
v[2] += that.v[2];
return *this;
}
};
vec operator+(const vec& lhs, const vec& rhs)
{
return vec(lhs.v[0] + rhs.v[0], lhs.v[1] + rhs.v[1], lhs.v[2] + rhs.v[2]);
}
vec&& operator+(vec&& lhs, const vec& rhs)
{
return move(lhs += …Run Code Online (Sandbox Code Playgroud) 在一个变量中使用std :: move之后,该变量可能是类中的一个字段,如:
class A {
public:
vector<string>&& stealVector() {
return std::move(myVector);
}
void recreateMyVector() {
}
private:
vector<string> myVector;
};
Run Code Online (Sandbox Code Playgroud)
我如何重新创建矢量,就像一个清晰的矢量?在std :: move之后myVector中还剩下什么?
我在anwser中看到过: 通过右值引用返回更有效率吗?
成员函数定义:
Beta_ab const& getAB() const& { return ab; }
Run Code Online (Sandbox Code Playgroud)
我熟悉成员函数的cv-qualifier(const),但不熟悉const&.
最后的const&意思是什么?
在Scott Meyer的新书中,他提出了rvalue引用限定符的示例用法,如下所示:
class Widget {
private:
DataType values;
public:
DataType& data() & { return values; }
DataType data() && { return std::move(values); } // why DataType?
};
Run Code Online (Sandbox Code Playgroud)
以便:
auto values = makeWidget().data();
Run Code Online (Sandbox Code Playgroud)
移动构造values而不是复制构造它.
为什么rvalue-ref-qualified data()返回DataType而不是DataType&&?在这种情况下auto仍会推断DataType(虽然decltype(auto)不会 - 但这不是唯一的理由,更喜欢返回一个值而不是ravlue ref).这个高度投票的答案会返回一个rvalue ref,这对我来说在概念上更有意义.
我想实现一个填充向量然后返回右值引用的函数.我厌倦了:
std::vector<int> &&fill_list() {
std::vector<int> res;
... do something to fill res ...
return res;
}
int main(int argc, char **argv) {
std::vector<int> myvec = fill_list();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但这不起作用,我收到以下错误:
error: invalid initialization of reference of type 'std::vector<int>&&' from expression of type 'std::vector<int>'
Run Code Online (Sandbox Code Playgroud)
总而言之,正确的做法是怎样的?我认为我还没有获得右值参考.