1

我正在向由第三方库定义的类添加辅助函数。此函数就地修改对象。如果我将函数编写为方法,它将如下所示:

myObject &doTheThing( int someParameter ) {
    myProperty = someParameter;
    return *this;
}

所以它可以被称为:

myInstance = instance1 + instance2;
myInstance.doTheThing( );

或者

display( (instance1 + instance2).doTheThing( ) );

哪个工作正常。但是由于我无法扩展对象,所以我将其编写为辅助函数;

myObject &doTheThing( myObject &object, int someParameter ) {
    object.myProperty = someParameter;
    return object;
}

这在第二个用例中无效,因为临时无法绑定到非常量引用(人为的测试用例:http ://codepad.org/5frJjCUb )。有没有办法在不使用 pass-by-copy 的情况下解决这个问题?如果复制是唯一的方法,是否有一些最佳实践方法可以帮助编译器正确优化它?(C ++ 11 很好)

4

3 回答 3

2

您可以使用 c++11 解决它rvalue

r 值引用参数的目的是专门检测对象何时是 r 值。因为如果一个对象是一个右值,那么函数就知道它不会被再次使用,所以它可以用它做任何它想做的事情。

您可以重载该功能:

myObject &doTheThing( myObject &object, int someParameter ) {
    object.myProperty = someParameter;
    return object;
}

myObject &doTheThing( myObject &&object, int someParameter ) {
    //                         ^^
    object.myProperty = someParameter;
    return object;
}

保留你的实现,只添加一个,rvalue因为当我一开始谈论的检测没有发生时,你必须有一个函数来lvalue引用。

例如 :

doTheThing( instance1 + instance2, 1 ) // uses the rvalue implementation
doTheThing( myInstance, 1);            // uses the lvalue implementation

编辑 : 正如评论中所说,您可以跳过重载实现但这导致了最后一个问题:使用rvalue引用似乎可以解决问题,但如果我们进一步观察:使用创建的临时对象(instance1 + instance2)将在doTheThing. 一个解决方案可能是:

myObject &doTheThing( myObject &object, int someParameter ) {
    object.myProperty = someParameter;
    return object;
}

myObject doTheThing( myObject &&object, int someParameter ) {
    //  ^
    object.myProperty = someParameter;
    return object;
}

超载的价值回报将避免一些生活问题。

但是您现在不能跳过重载实现,因为编译器会生成此错误:

error C2664: 'concat' : cannot convert parameter 1 from 'MyObj' to 'MyObj &&'
    You cannot bind an lvalue to an rvalue reference
于 2013-07-22T12:59:07.273 回答
1

您可以重载辅助函数以获取右值引用,这将在第二种情况下起作用:

myObject &doTheThing( myObject &&object, int someParameter ) {
    object.myProperty = someParameter;
    return object;
}

请注意,您需要该函数的两个版本:一个采用引用,另一个采用右值引用。

于 2013-07-22T12:58:08.657 回答
0

按值取参数,按值返回

将您的代码更改为

myObject doTheThing( myObject object, int someParameter ) {
    object.myProperty = someParameter;
    return object;
}

一切都应该正常工作。从 C++11 开始,如果从临时对象创建,该对象将被简单地移动到您的参数列表中。这同样适用于返回值。在您的情况下,编译器甚至可以选择省略移动构造并根据调用的上下文避免这两个移动。

doTheThing(bla, blub)这显然改变了变化的含义。如果要使用此函数修改对象,则必须编写

bla = doTheThing( bla, blub );

反而。这看起来不太好,但提供了更好推理的值语义。但它解决了你的问题,没有以下陷阱。

R 值参考不是解决方案

乍一看,您似乎可以使用右值引用来解决这个问题,但事实证明这是不安全的。如果你定义了这两个函数

myObject &  doTheThing( myObject &  object, int someParameter );
myObject && doTheThing( myObject && object, int someParameter );

然后写

auto && obj = doTheThing( createTemporary(), 5 );
doSomethingElse( obj );

将返回的引用的生命周期延长到obj. 但是,创建的对象createTemporary()将在第一行的末尾被销毁。因此obj,在第二行访问将导致未定义的行为。

于 2013-07-22T14:00:45.627 回答