以下哪个示例是声明以下功能的更好方法?为什么?
void myFunction (const int &myArgument);
Run Code Online (Sandbox Code Playgroud)
要么
void myFunction (int myArgument);
Run Code Online (Sandbox Code Playgroud)
Ale*_*tov 38
使用const T & argif sizeof(T)>sizeof(void*)和use T argifsizeof(T) <= sizeof(void*)
Meh*_*ari 20
他们做不同的事情.const T&使该函数接受对变量的引用.另一方面,T arg 将调用对象的复制构造函数并传递副本.如果复制构造函数不可访问(例如它private),T arg将无法工作:
class Demo {
public: Demo() {}
private: Demo(const Demo& t) { }
};
void foo(Demo t) { }
int main() {
Demo t;
foo(t); // error: cannot copy `t`.
return 0;
}
Run Code Online (Sandbox Code Playgroud)
对于像原始类型这样的小值(其中所有重要的是对象的内容,而不是实际的引用标识;比如,它不是句柄或其他东西),T arg通常是首选.对于无法复制和/或保留引用标识的大对象和对象很重要(无论大小如何),首选传递引用.
另一个优点T arg是,由于它是副本,被调用者不能恶意改变原始值.它可以像任何局部变量一样自由地改变变量来完成它的工作.
Joh*_*itb 14
取自Move构造函数.我喜欢简单的规则
如果函数打算将参数更改为副作用,则通过引用/指针将其作为非const对象.例:
void Transmogrify(Widget& toChange);
void Increment(int* pToBump);
Run Code Online (Sandbox Code Playgroud)如果函数不修改其参数且参数是基本类型,则按值取值.例:
double Cube(double value);
Run Code Online (Sandbox Code Playgroud)除此以外
3.1.如果函数始终在其中复制其参数,请按值取值.
3.2.如果函数从不复制其参数,则通过引用const来获取它.
3.3.我添加:如果该功能有时复制,那么决定直觉:如果副本几乎总是完成,那么按值进行.如果复制完成了一半的时间,那么请以安全的方式参考const.
在您的情况下,您应该通过值获取int,因为您不打算修改参数,并且参数是基本类型.我认为"原始类型"可以是非类型类型,也可以是没有用户定义的复制构造函数的类型,其中sizeof(T)只有几个字节.
有一个流行的建议,指出应该根据你要传递的类型的实际大小来选择传递方法("按值"与"通过const引用").即使在这个讨论中,你也有一个标记为"正确"的答案.
实际上,根据类型的大小做出决定不仅是不正确的,这是一个 重大且相当明显的设计错误,表明严重缺乏对良好编程实践的直觉/理解.
基于对象的实际依赖于实现的物理大小的决策必须尽可能多地留给编译器.尝试通过对传递方法进行硬编码来"调整"代码到这些大小是对100个中的99个案例的完全适得其反的浪费.(是的,确实如此,在C++语言的情况下,编译器不会有足够的自由可以互换地使用这些方法 - 在一般情况下它们在C++中并不是真的可以互换.虽然如果有必要,可以通过模板元编程实现适当的基于大小的[半]自动传递方法选择;但这是一个不同的故事).
在"手动"编写代码时选择传递方法的更有意义的标准可能听起来如下:
当您传递一个原子的,单一的,不可分割的实体时,更喜欢传递"by value",例如任何类型的单个非聚合值 - 数字,指针,迭代器.请注意,例如,迭代器是逻辑级别的单一值.因此,不管它们的实际大小是否大于sizeof(void*),都希望按值传递迭代器.(STL实现就是这样,BTW).
当您传递任何类型的聚合值时,更喜欢传递"by const reference".即在逻辑级别上暴露出明显"复合"性质的值,即使其大小不大于sizeof(void*).
两者之间的分离并不总是很清楚,但是所有这些建议总是如此.此外,分离成"原子"和"复合"实体可能取决于您的设计的具体情况,因此决策实际上可能因设计而异.
请注意,此规则可能会产生与本讨论中提到的所谓"正确"基于大小的方法不同的决策.
作为一个例子,它倾向于观察,基于大小的方法将建议您手动硬编码不同类型的迭代器的不同传递方法,具体取决于它们的物理大小.这使得基于大小的方法是多么虚伪是特别明显的.
再一次,良好的编程实践所依据的基本原则之一是避免将您的决策建立在平台的物理特性上(尽可能多).相反,您的决策必须基于程序中实体的逻辑和概念属性(尽可能多).传递"按价值"或"按参考"的问题在这里也不例外.
在C++ 11中,将移动语义引入语言产生了不同参数传递方法的相对优先级的显着转变.在某些情况下,按值传递复杂对象可能变得完全可行
是否应将C++ 11中的所有/大多数setter函数编写为接受通用引用的函数模板?
与流行的和长期存在的信念相反,即使你传递一个大型物体,传递const引用也不一定更快.您可能想阅读Dave Abrahams最近 关于这个主题的文章.
编辑:(主要是回应Jeff Hardy的评论):在最大数量的情况下,通过const引用传递可能是"最安全"的选择 - 但这并不意味着它总是最好的事情.但是,为了理解这里讨论的是什么,你真的需要仔细阅读Dave的整篇文章,因为它相当技术性,其结论背后的推理并不总是直观明显(你需要理解做出明智选择的理由) ).
| 归档时间: |
|
| 查看次数: |
5950 次 |
| 最近记录: |