C++&引用;“最佳”;参数传递法 我今天编写了一个C++类,我写了一个函数,它把一个参数当作一个引用而不是一个指针,这是我很少做过的。我总是通过指针。所以我正要把它改回去,然后我意识到——我不知道我是否应该,或者它是否重要
所以我转向你们。我有三种传递参数的方法:C++&引用;“最佳”;参数传递法 我今天编写了一个C++类,我写了一个函数,它把一个参数当作一个引用而不是一个指针,这是我很少做过的。我总是通过指针。所以我正要把它改回去,然后我意识到——我不知道我是否应该,或者它是否重要,c++,performance,coding-style,parameter-passing,C++,Performance,Coding Style,Parameter Passing,所以我转向你们。我有三种传递参数的方法: //1: By pointer Object* foo(Object* bar) {…} //2: By reference Object& foo(Object& bar) {…} //3: By value (just for completeness) Object foo(Object bar) {…} 假设#3是出于性能原因(是的,我知道编译器在这方面做得很好,但仍然如此),那么其他两个或多或少是等效的 那么,“最好”的方
//1: By pointer
Object* foo(Object* bar) {…}
//2: By reference
Object& foo(Object& bar) {…}
//3: By value (just for completeness)
Object foo(Object bar) {…}
假设#3是出于性能原因(是的,我知道编译器在这方面做得很好,但仍然如此),那么其他两个或多或少是等效的
那么,“最好”的方法是什么?指针?推荐人?两者的某种结合?或者这有什么关系?技术上的原因是最好的,但风格上的原因同样好
更新:我接受了YeenFei的答案,因为它解决了让我得到答案的差异(即使我当时故意忽略了他的建议——我喜欢选择NULL…)。但每个人都提出了很好的观点,尤其是GMan(在评论中)和Nemo,在回答性能和价值传递时。如果你在这里寻找答案,请全部核对 如果你自己设计所有东西,任何时候都可以参考。惯用的现代C++几乎不应该在任何地方都有原始指针。动态分配的对象应该在资源管理容器中移动(
shared_ptr
或unique_ptr
,或弱_ptr
,如果适用),但对于大多数操作,传递(const)引用是传递需要修改的参数或重载类型参数的主要方式。不要忘记,如果您有可移动的类型,按值传递可能是一个可行的选项。按指针传递和按引用传递实际上是相同的,只是语法不同。我更喜欢通过指针传递,因为它使事情变得明确:
Object bar;
ptr_foo(&bar); // bar may change
ref_foo(bar); // can bar change? Now I need to go look at the prototype...
val_foo(bar); // bar cannot change. (Unless you use references here and there)
传递值和指针之间唯一的技术偏好,正如您所提到的,是类是否足够大,从而使其传递速度变慢。如果预期参数有效,我建议通过引用传递参数。这将是一个由设计优化和节省您从 引用不能为空,而指针可以为空。
如果您处理的是指针,那么在使用它们之前,您需要验证给定指针是否有效(非空),无论它是原始形式还是包装在托管容器(共享的)中。因此我将为选择提供理由#3。考虑下面的代码:
struct Foo {
int x;
int y;
};
Foo
add(Foo a, Foo b)
{
Foo result;
result.x = a.x + b.x;
result.y = a.y + b.y;
return result;
}
Foo
add2(Foo &a, Foo &b)
{
Foo result;
result.x = a.x + b.x;
result.y = a.y + b.y;
return result;
}
尝试检查生成的程序集。请注意,add
几乎完全是注册操作,安排得很好。请注意,add2
是如何在没有任何重新排序的情况下进行大量内存访问的
我写了一个main
,它调用了这些函数100亿次。结果如何add
耗时22秒,而add2
耗时26秒。即使对于这个简单的示例,传递值版本的性能也提高了10-20%
好的,结构很简单。但功能也是如此。函数越复杂,传递值版本越可能更快,因为编译器知道这两个参数不会“重叠”。这对优化是一个巨大的好处
当然,这个决定应该主要基于函数的语义:是否需要NULL作为合法值?如果是这样,显然你需要一个指针。是否需要修改对象?然后使用指针或引用
但是,如果不需要修改对象,则更愿意按值传递它们,除非对象很大和/或具有非平凡的复制构造函数(例如std::string)。若by value真的太慢,请按常量的引用或指向常量的指针传递
但是,不要低估按值传递的潜在速度优势,它源自寄存器与内存和指令重新排序的优势。请注意,随着每一代CPU的出现,这些优势变得更加明显。使用:
您可以查看库,它会自动将类型转换为最佳参数类型。由于您省略了函数体,我猜您认为它是不相关的。我向你保证这不是最好的,为了什么?如果要引用对象,请使用引用。如果要指向某个对象,或者可能根本没有对象(null),请使用指针。如果您想要自己的副本,请使用一个值。无论原因是什么,性能都不是其中之一。不同意性能不是问题。事实上,对于小物体,#3几乎肯定会是最快的。。。别名问题往往会导致指针和引用生成比值慢的代码。通常要慢得多。嗯,复制构造给定对象总是比指针/引用慢。@YeenFei,如果对象不包含太多数据(例如单个int),则传递值的速度更快。@Mark Ransom,这是一个有趣的点(尽管我们都知道设计的对象在大多数情况下都比指针/引用大得多)。你介意让我看一看解释原因的文章吗?除了每个接受指针的函数都必须处理null之外,如果你的程序要正确的话。@YeenFei:你完全错了。尽管参数本身的传递速度可能更快,但生成的代码几乎肯定会更糟,而且会弥补更多。由于别名关注的内存容量过高/存储量是C++优化的阿基里斯的后端。如果不采取措施防止引用,那么引用可能是空的(即坏的)。但你的观点是不必检查参考资料