从 cpp 文档中std::vector
,我看到了这一点:
void push_back ( const T& x );
我知道这push_back
会复制我传递的对象。但是,为什么是签名const T& ?
通过查看这个,我最初认为它需要const
引用我推送到vector
.
另一种选择是
void push_back(T x);
即x
按价值取值。但是,这会(在 C++03 中)导致创建一个额外x
的副本(在 的参数中的副本push_back
)。通过constx
引用可以避免这种情况。
让我们看一下按值调用的堆栈v.push_back(T())
:
v.push_back(T()); // instance of T
void std::vector<T>::push_back(T x) // copy of T
new (data_[size_ - 1]) T(x) // copy of copy of T
通过 const 引用我们得到:
v.push_back(T()); // instance of T
void std::vector<T>::push_back(const T &x) // const reference to T
new (data_[size_ - 1]) T(x) // copy of T
在 C++11 中,可以(尽管没有必要)x
按值获取并使用std::move
将其移动到向量上:
v.push_back(T()); // instance of T
void std::vector<T>::push_back(T x) // copy of T
new (data_[size_ - 1]) T(std::move(x)) // move the copy of T
只是为了澄清@ecatmur 描述的“额外副本”,如果push_back
按值接收它的参数,会发生什么事情是你将从你的对象开始。其副本将push_back
作为其参数传递给。然后push_back
将创建一个副本以放入向量本身。
由于真正的实现push_back
通过引用接收它的参数,它(push_back
)直接在向量中创建新对象作为原始对象的副本。
如前所述,是的,使用 C++11 使用移动语义,可以(尽管可能不是特别有利)按值传递参数,然后将值从该参数移动到向量中的新对象中。例如,如果您放入向量中的是一个字符串,该字符串主要包含一个指针和几个“簿记”字段(分配的内存量,当前使用的内存量),那几乎和传递一个引用,因为移动只能做一个浅拷贝——复制指针和簿记值本身,而不是它指向的所有数据。但是,如果所讨论的对象直接保存其所有数据(即,不是指针),那么移动将与复制一样慢。
通过引用传递,避免了所有的复制,所以即使对于像字符串这样的东西,它通常也更快(对于像这样的情况,原始对象不能被无效)。它还具有使用 C++98/03 的次要优势,而不仅仅是 C++11。
object
你 push 是通过引用传递的,以避免extra copy
。比副本放置在vector
.