函数参数:复制还是指针?

9
我有一些关于 C++ 的问题,希望你能帮我解答其中之一。
在使用需要一个或多个参数的函数时,如果你知道这些参数将始终存储在变量中,那么是否有任何理由传递变量的副本而不是指向变量的指针?
我想讨论的是性能方面。对我来说,传递整个结构体的副本似乎需要更多的资源,而只传递指针(4 个字节)则不用。
6个回答

12

传递副本比传递指针更便宜的方式有几种。

  1. 对象等于或小于指针。直接访问值总是比解引用指针快。
  2. 结构体足够小,可以由编译器放在堆栈上。在这种情况下,对结构体中的值的访问是通过索引寻址模式而不是间接寻址模式完成的。前者通常更快。

还有其他原因希望传递副本而不是引用,即函数将对结构体进行更改,这些更改不会反映回调用者。虽然这通常是不好的做法,但将参数按值传递将确保不会错误地更改调用者的视图。

现在是你可能不想听到的部分:这通常并没有那么大的区别!使用最符合程序语义的参数传递方法。如果您后来发现特定区域存在性能瓶颈,则重点关注提高该处性能。不要过度优化!


10
通过指针(或引用)传递对象和传递相同对象的副本具有不同的语义。如果您希望在函数调用外部反映对对象所做的更改,则需要引用语义,否则需要值语义。
通常,可以通过按值传递值或通过const引用来表达值语义。
void value_semantics(my_obj obj);
void value_semantics(const my_obj& obj);

然而,使用const引用的方式也存在一些缺点,它会防止编译器因别名问题而进行的一些优化;对于具有平凡构造函数的对象而言,额外的间接层次(引用被实现为指针)可能会抵消避免复制所带来的好处。
为了获得引用语义,您可以选择通过引用或指针传递,正如其他人已经说过的,引用在C++中比指针更自然(您不必使用地址运算符&),指针的唯一真正优势是如果您想启用NULL值。
经验法则是对于非平凡类应该通过const引用传递,否则通过值传递。

4

指针容易引起错误,因为它允许被调用者更改对象。指针可以为0,这往往会导致崩溃,并且需要在各个地方测试0指针,这可能很烦人。使用C++引用,在可能的情况下声明const可以避免这两个问题。


int * ohoh = new int; delete ohoh; cout << ohoh; // 非0空指针 - MattyT
这就是为什么我不会测试空指针(除非明确指出函数可能返回空指针)。空指针只是全局“无效指针”问题的一个很小的子集。为什么我们不检查例如1将明显无效,就像0一样(有少数例外情况,其中0也是有效的)... - Ilya

4
避免使用指针。如果是输入参数,请使用常量引用;否则,只需使用引用作为输入输出参数。

2
主要问题不在于性能,而在于语义,以及您的函数是否修改结构中的数据。
如果您的函数修改了结构,则传递指针将允许调用者查看结构中的更改数据。在这种情况下,传递副本可能是错误的,因为您的函数将修改一个副本,然后(可能)被丢弃。当然,可能您的函数修改了数据,但您不希望进行修改,这种情况下复制是正确的做法,以保护原始值免受更改。
如果您的函数不修改结构,则没有理由复制值,因为它们只会被读取。
如果您对将结构指针传递给函数的概念感到不舒服,那么您应该练习一下,因为这是C和C++中处理结构的典型方式。
就性能而言,复制结构需要更多的工作,但在整个方案中相对较小。首先要关注代码的语义。

1

如果它们不会改变,那么引用更常见,或者是一个const引用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接