在C++函数中的适当位置处理参数
Work on a parameter in-place in C++ function
我正在向由第三方库定义的类添加一个辅助函数。此函数用于在适当位置修改对象。如果我把函数作为一种方法来编写,它会是这样的:
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很好)
您可以使用c++11 rvalue
来解决它。
r值参考参数的目的是专门检测对象何时为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
您可以重载您的助手函数以获取右值引用,这将在第二种情况下起作用:
myObject &doTheThing( myObject &&object, int someParameter ) {
object.myProperty = someParameter;
return object;
}
请注意,您需要两个版本的函数:一个使用引用,另一个使用右值引用。
按值获取参数并按值返回
将代码更改为
myObject doTheThing( myObject object, int someParameter ) {
object.myProperty = someParameter;
return object;
}
一切都应该很好。由于C++11,对象将被简单地移动到您的参数列表中,如果是从临时创建的。返回值也是如此。在您的情况下,编译器甚至可以选择省略move构造,并根据调用的上下文来避免这两个移动。
这使CCD_ 7的意义发生了明显的变化。如果你想用这个函数修改一个对象,那么你必须写
bla = doTheThing( bla, blub );
相反。这看起来不太好,但提供了更好推理的价值语义。但它解决了你的问题,没有以下陷阱。
R值参考不是解决方案
乍一看,你似乎可以用右值引用来解决这个问题,但这是不安全的如果您定义的两个功能
myObject & doTheThing( myObject & object, int someParameter );
myObject && doTheThing( myObject && object, int someParameter );
然后写入
auto && obj = doTheThing( createTemporary(), 5 );
doSomethingElse( obj );
将把返回的引用的生存期延长到CCD_ 8的作用域。但是,createTemporary()
创建的对象将在第一行的末尾被销毁。因此,访问第二行中的CCD_ 10将导致未定义的行为。
- 0x0F50DF58:0xC0000005:访问冲突读取位置0x0047CA04时未处理的异常
- 错误 在测试.exe 0x76C9FD62时出现未经处理的异常:Microsoft C++异常:内存位置0x006FF8
- Box2D 如何处理位置和坐标?
- 最简单的方法使多个指针一次指向同一位置,一次只处理2个位置
- 如何处理更改插入符号位置的事件
- 如何修复<程序名称>中的"<内存位置>未处理的异常。Visual Studio 2017 中的访问冲突写入位置<内存位置>"
- ***读取位置*******的访问冲突处出现未处理的异常
- 在0x77081D76(ntdll.dll)中未经处理的例外.Exe:0xc0000005:访问违规写作位置0x0000
- NVIDIA 在 <work.exe>0xC0000005 中0x002a2da2未处理的异常:访问违规读取位置0x00000000
- 未处理的异常..访问冲突写入位置
- 在 DirectXGame.exe 中0x00B84CD6出现未经处理的异常:0xC0000005:访问冲突读取位置0x
- 存储类对象的C++模板链表-未处理的异常访问冲突读取位置
- 未处理的异常:_com_error内存位置 0x0040f4ac
- Dijkstra 中0x001e1078 s_Algorithm.exe的未处理异常:0xC0000005:访问冲突读取位置0xbaadf00d
- 从未由着色器处理的位置光照基元
- 位置处未处理的异常:内存位置处的Microsoft C++异常:std::length_error
- 更改QGraphicsItems在场景事件处理程序中的位置
- 读取位置/使用结构的矢量时发生未处理的异常访问冲突
- 使用新位置处理内存
- 在C++函数中的适当位置处理参数