我看到了与此类似的问题,但我想澄清一下...
假设一个基本的C ++类:
class MyClass
{
public:
struct SomeData
{
std::wstring name;
std::vector<int> someValues;
};
void DoSomething(const SomeData data);
}
我知道data
将作为const
传递给DoSomething
,这是可以的,因为data
不会被函数以任何方式修改...但是我习惯看到&
用const
参数指定以确保它们通过引用传递,例如
void DoSomething(const SomeData& data);
对我来说,这似乎更有效率。如果我们省略&
,那么data
是否不是按值传递给DoSomething
的?我不确定为什么可以通过引用传递并避免复制发生时,最好按值传递const
参数?
答案 0 :(得分:3)
按值/引用传递和const正确性是两个不同的概念。但是一起使用。
按值传递
void DoSomething (SomeData data);
按值传递用于复制成本较低且不想保留对异物的引用的情况。在某些情况下,此函数可以(如果在类中)保留指向此对象的指针并拥有自己的副本。
通过引用传递
void DoSomething (SomeData& data);
如果您知道复制结构可能会导致性能下降,请始终使用按引用传递。在某些情况下,此函数可以(如果在类中)保留指向此对象的指针并指向异物。保持指向异物的指针意味着您应该了解它的寿命以及该异物何时超出范围。更重要的是,对异物的更改会显示在您的指针上。
常量正确性
void DoSomething (const SomeData data); // const for local copy
void DoSomething (const SomeData& data); // const for callers object
添加const
以按值或引用传递表示此函数不会更改它。但没有&
还是没有决定您要增加修改安全性的对象。 const
就文档API而言,是C ++中非常有用的工具,可提供编译时安全性,并允许更多编译器优化。
Read本文。
答案 1 :(得分:1)
void DoSomething(const SomeData data)
的最大问题在于它使接口和实现变得模糊。从呼叫者的角度来看,const
并没有任何改变。该函数仍然会收到一个副本,并且原始对象不会被修改。该实现对自己的函数内部副本执行的操作或不执行的操作不应打扰调用方,因此不应在接口中表示。
如果不更改副本,const
的确会使实现更加const正确,但是将实现细节泄漏到接口中需要付出很高的代价。我建议不要使用void DoSomething(const SomeData data)
。
与往常一样,此处的绩效收益或损失不应高估。更多关于语义和约定的信息。
答案 2 :(得分:0)
传递const
值对于调用者来说主要是信息性的,它表明了意图。这对于使代码易于阅读,理解和维护很重要。
如果编译器知道该函数未修改其参数,也可能会添加一些额外的优化。例如,这可能会导致编译器根本不执行复制。
答案 3 :(得分:0)
此:
void DoSomething(const SomeData data);
有点不寻常,因为尽管它对于调用方(可以传递const或非const值)不做任何更改,但它限制了函数可以在内部执行的操作。这样做的价值不高,而且通常不做。
如果复制值昂贵,包括在目标平台上大约大于两个指针,则按引用传递(是否传递const)会更有效。换句话说,如果SomeData
是包含两个整数的结构,则按值传递它可能会更有效。但是,如果其中包含std::map
或一些较大的数据,最好通过引用将其传递。
一个例外是,如果函数仍然要复制该值,则最好按值取值,因为如果调用者允许,则该值可能是“移动的”,而不是复制的。