因为 const
引用与传递值基本相同,但不会创建副本(据我所知)。所以有没有需要创建变量副本的情况(这样我们就需要使用按值传递)。
因为 const
引用与传递值基本相同,但不会创建副本(据我所知)。所以有没有需要创建变量副本的情况(这样我们就需要使用按值传递)。
有些情况下,你不需要修改输入参数,但仍然需要它的一个内部副本,此时你可以考虑通过值传递参数。比如说,假设你有一个函数可以返回已排序的向量副本:
template <typename V> V sorted_copy_1(V const & v)
{
V v_copy = v;
std::sort(v_copy.begin(), v_copy.end());
return v;
}
这样做没有问题,但如果用户有一个向量,他们从未需要用于任何其他目的,则必须在此处进行强制复制,这可能是不必要的。因此,只需按值传递参数:
template <typename V> V sorted_copy_2(V v)
{
std::sort(v.begin(), v.end());
return v;
}
现在,生成、排序和返回向量的整个过程基本上可以“原地”完成。
较便宜的示例是算法,它们消耗计数器或迭代器,在算法过程中需要修改它们。同样,通过值传递这些参数允许您直接使用函数参数,而不需要创建局部副本。
const
引用和对象? - Johnson像许多事情一样,这是一个平衡问题。
我们通过const引用传递以避免复制对象。
当您传递const引用时,您传递了一个指针(引用是具有额外糖分的指针,使它们口感不那么苦)。当然,假设对象是可以轻松复制的。
要访问引用,编译器必须解引用指针以获取内容[假设它无法内联并且编译器优化掉解引用,但在这种情况下,它也将优化掉额外的复制,因此从按值传递中没有损失]。
因此,如果您的复制比解引用和传递指针的总和“便宜”,则当您按值传递时,您会“赢得胜利”。
当然,如果您无论如何都要进行复制,那么最好在构造参数时进行复制,而不是稍后显式复制。
C& operator=(C other)
{
swap(*this, other);
return *this;
}
other
通过值传递而不是通过 const 引用传递,可以更轻松地编写正确的赋值运算符,避免代码重复并提供强异常保证!std::partition
这样的算法必须立即复制其输入,这既低效又看起来很傻。我们都知道避免看起来傻的代码是第一要务。template<class BidirIt, class UnaryPredicate>
BidirIt partition(BidirIt first, BidirIt last, UnaryPredicate p)
{
while (1) {
while ((first != last) && p(*first)) {
++first;
}
if (first == last--) break;
while ((first != last) && !p(*last)) {
--last;
}
if (first == last) break;
std::iter_swap(first++, last);
}
return first;
}
const&
引用不能在没有通过 const_cast
改变其值的情况下进行更改,但是它可以被更改。在代码离开编译器的“分析范围”的任何时候(可能是调用不同编译单元的函数,或通过函数指针无法在编译时确定其值),它必须假定所引用的值可能已经改变。const&
来承担这个成本。const&
获取一个std::string
,然后创建一个本地副本,则可能需要创建一个std::string
以传递该参数,另一个则为本地副本。std::string
,则只会创建一个副本(并可能被移动)。std::string some_external_state;
void foo( std::string const& str ) {
some_external_state = str;
}
void bar( std::string str ) {
some_external_state = std::move(str);
}
int main() {
foo("Hello world!");
bar("Goodbye cruel world.");
}
foo
会创建一个包含"Hello world!"
的std::string
,然后再将其复制到some_external_state
中。总共创建了2个副本,丢弃了1个字符串。bar
直接创建了std::string
参数。然后将其状态移动到some_external_state
中。总共创建了1个副本,进行了1次移动,丢弃了1个(空)字符串。bar
之外,而foo
可能会抛出资源耗尽的异常。int
)的非优化ABI直接复制比const&
参数的非优化ABI更快。这主要涉及编写无法或不会进行优化的接口,并且通常是微观优化。const&
引用。而那些复制成本较低的东西,几乎总是应该按值传递。而介于两者之间的东西则需要认真思考。 - Yakk - Adam NevraumontFoo
的实例时,通常 你知道 Foo
是什么以及你正在做什么(大致上)。你是在制作本地副本吗?Foo
是否可以便宜地移动?那就按值传递。Foo
是否是一种便宜的复制类型?那就按值传递。你是否真的希望外部 Foo
的更改传递到函数中间的参数中?那就按 const&
传递。Foo
是否很难复制且没有简单的 move
?那就按 const&
传递。只有少量具体参数能通过上述测试组合。 - Yakk - Adam Nevraumont