有效地返回未修改的参数
Returning unmodified argument efficiently
我有一个函数,它应该修改对象的实例,或者不修改地返回它,可以简化为以下代码:
struct MyObject
{
bool ShouldNotChange;
int SomeData[10];
};
void ModifyObject_inplace(MyObject & object)
{
if (object.ShouldNotChange) return;
// Modify object here
object.SomeData[1] = 1;
}
出于多种原因,我想将此代码转换为更实用的样式:
MyObject ModifyObject(MyObject object)
{
if (object.ShouldNotChange)
return object;
object.SomeData[1] = 1;
return object;
}
问题是,该功能对性能至关重要,当以这种方式进行修改时,速度会变慢。我尝试了几种不同的变体。
MyObject ModifyObject_constref(const MyObject & object)
{
if (object.ShouldNotChange)
return object;
auto result = object;
result.SomeData[1] = 1;
return result;
}
std::shared_ptr<MyObject> ModifyObject_ptr(const std::shared_ptr<MyObject> & object_ptr)
{
if (object_ptr->ShouldNotChange)
return object_ptr;
object_ptr->SomeData[1] = 1;
return object_ptr;
}
MyObject && ModifyObject_rvalue(MyObject object)
{
if (object.ShouldNotChange)
return std::move(object);
MyObject newRoute = object;
newRoute.SomeData[1] = 1;
return std::move(newRoute);
}
但只有ModifyObject_inplace
给出了最快的代码(通过反汇编判断)。事实上,只有ModifyObject_inplace
被编译器翻译成一个函数,而没有在汇编代码中进行一次跳转。我正在使用VC++2017。
有没有什么方法可以在不影响性能的情况下以功能风格实现它?
您可以拥有:
MyObject& ModifyObject(MyObject& object)
{
if (object.ShouldNotChange) return object;
// Modify object here
object.SomeData[1] = 1;
return object;
}
如果您需要const参数,那么将需要一些副本,这将比就地修改+引用返回更昂贵。
分析您的尝试
MyObject ModifyObject(MyObject object)
这将至少涉及对象的一个副本。当你可以避免这种情况时,这并不理想。
MyObject ModifyObject_constref(const MyObject & object)
同样,您需要将参数复制到返回对象中。同样的问题。
std::shared_ptr<MyObject> ModifyObject_ptr(const std::shared_ptr<MyObject> & object_ptr)
不,不,不…不!当具有不同生存期的多个对象是资源的所有者时,shared_ptr
用于管理资源生存期。这就是它的用法。时期如果您没有这种情况,请不要使用shared_ptr
。此外,shared_ptr
对性能有非常显著的影响。至少有一个外部共享状态和2个与shared_ptr
相关联的间接性。
MyObject && ModifyObject_rvalue(MyObject object)
// ...
return std::move(object);
未定义的行为!返回对函数参数的引用。当函数结束时,object
结束了它的生命周期——你最终引用了一个死对象。同样,在你的情况下,移动相当于复制。MyObject
中没有可以在移动中被盗的资源,因此移动实际上执行复制。
解决方案
正如Jarod42
向您展示的
MyObject& ModifyObject(MyObject& object)
是最快的一个,因为你只需要四处传递引用。没有创建新对象,也没有进行复制。
必须返回值。理想情况下,常量参数
如果您有一个const参数,并且需要返回一个修改过的对象,那么您肯定需要创建一个新对象,这涉及到一个副本。如果这是你的要求,那么我会选择:
MyObject ModifyObject_1(MyObject object)
{
if (!object.ShouldNotChange)
object.SomeData[1] = 1;
return object;
}
或
MyObject ModifyObject_2(const MyObject& object)
{
MyObject r{object};
if (!r.ShouldNotChange)
r.SomeData[1] = 1;
return r;
}
或
MyObject ModifyObject_3(const MyObject& object)
{
if (object.ShouldNotChange)
return object;
MyObject r{object};
r.SomeData[1] = 1;
return r;
}
这些中哪一个最快?您需要配置,无论如何都应该这样做。不要从汇编中得出结论,除非它们得到了分析的支持。对于性能关键代码配置文件,配置文件,概要文件!
功能编程和性能
在纯函数代码中(这似乎是您想要的),所有对象都是不可变的。这意味着无论何时需要修改对象都要进行复制。这会对性能产生影响。你需要决定这个权衡是否值得。
您是否考虑过向MyObject添加方法?看起来您不需要返回不同对象的函数,而是需要一个修改或不修改对象的方法。如果需要,方法也可以返回此或对对象的引用。建议编译器内联可能比较好。
- 为什么当函数参数未定义为常量引用时存在无限递归?
- 执行参数未提供预期结果
- src/caffe/parallel.cpp:70:1:错误:“参数”未命名类型
- c++ 参数未传递到运算符重载中<
- Gettin 目标模式不包含来自未修改的生成文件的"%"?
- 使用指标后数组未修改
- 构造函数字符串参数未设置窗口标题
- 命令行参数未存储(使用 boost)
- 有效地返回未修改的参数
- 头文件中的函数参数"未在此范围内声明"
- 静态链接 MFC 时,未修改的 Visual Studio 2012 MFC 模板中出现链接错误
- C 参数参数未更新
- 是否可以在 C++ 中使用运算符重载来更改(未修改的)包含函数的含义
- 字符星形数组参数未正确终止
- libcurl curl_easy_stopt long参数未正确传递-varg(param,long)
- C++:自定义rand_int函数的参数未初始化
- 使用 SQL Server 和 Oracle 中的字符串使用相同的未修改查询进行连接
- 未修改 CUDA 内核函数输出变量
- 虚函数的参数未在所有子类中使用;有什么更好的设计方法吗?
- 如何标记 constexpr 函数的参数未使用?