可以采用许多不同的方式获取参数:
void foo(T obj);
void foo(const T obj);
void foo(T& obj);
void foo(const T& obj);
void foo(T&& obj);
void foo(const T&& obj);
Run Code Online (Sandbox Code Playgroud)
我不包括通过指针获取参数,因为指针可能已经是类型了T。
前两种方式是按值获取对象,这将导致对象被复制(如果没有通过智能编译器进行优化)。
其他方式是通过引用获取对象(前两个通过l值引用,后两个作为r值引用),该对象应省略复制。该const合格版本承诺不修改引用的对象。
如果我希望函数能够将所有类型的值(变量,从函数返回的临时值,文字等)作为参数,那么对于非对象修改版本(const)和潜在对象修改版本的原型应该是什么?版本(不是const)版本,如果我希望它最有效(避免调用复制构造函数,移动构造函数,赋值运算符,创建临时对象等)?
我不确定应该使用哪种类型的引用。如果这是一个主观的问题,我正在寻找每种方法的利弊。
有所有这些用于参数声明的组合都存在的原因。这仅取决于您的需求:
void foo(T obj);
obj被修改[因此已被复制]foo 可以修改 obj [是副本]foo不进行修改,obj则仍然优先使用此方法const T&-假设T它很小(适合1-2个CPU寄存器)void foo(const T obj);
obj被修改[因此已被复制]foo 不能修改 objconst通常是帮助您发现错误。这就是为什么通常将其用于避免意外修改的原因obj。(例如if (obj = 5))void foo(T& obj);
objfoo 可以修改 objint,double等等),这意味着一个传递拷贝会更好。void foo(const T& obj);
obj被修改foo 不能修改 objvoid foo(T&& obj);
obj如果之后为空,则没有问题foo 可以 obj通过将信息移到另一个地方来窃取数据来进行修改。void foo(const T&& obj);
foo 不能修改 obj,这使得它很少有用有很多特殊情况,因此这不是完整的列表。
一些额外的位:
(const T& obj)通常(T obj)由于很多原因而不仅仅是糟糕。但是请记住,呼叫者总是可以T简单std::reference_wrapper<const T>地避免复制。但是,这可能会破坏功能。std::move,也要进行很多操作-假设类型具有必要的运算符。template <typename F> void execute(F f) { f(); }最后,值得分享的是Bisqwit从此视频制作的流程图,该图制作了精美的图形: