C++ STL 向量(Vector):Push_back 取引用

12

std::vector的cpp文档中,我看到了这样的内容:

void push_back ( const T& x );

我知道push_back会复制我传递的对象,但是为什么签名是const T&?看起来它应该接受一个vector中要推送的任何对象的const引用。


我会做到的。昨天我才意识到这一点,从那时起我就在做了。谢谢! - NPE
3个回答

15
另一种选择是:
void push_back(T x);

也就是说,按值传递参数 x。然而,在 C++03 中,这将导致创建一个额外的 x 的副本(即传递给 push_back 的参数中的副本)。通过以常量引用方式传递 x 可以避免这种情况。

让我们看一下按值传递参数 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

1
在C++11中最好仍然使用T const&(以及T&&重载),因为并非所有对象都可以高效地移动。 - R. Martinho Fernandes

9

为了避免额外的拷贝,你所推送的object是通过引用传递的。然后在vector中放置一个副本。


9
只是为了澄清@ecatmur所描述的“额外副本”,如果push_back通过值接收它的参数,那么会发生的是你会从你的对象开始。该对象的副本将作为参数传递给push_back。然后push_back将创建一个该副本的副本放入向量中。
由于push_back的实际实现接收其参数的引用,因此它(push_back)直接在向量中创建原始对象的副本作为新对象。
如已提到的,使用C++11的移动语义,通过值传递参数,然后将该参数中的值移动到向量中的新对象中是可能的(尽管可能没有特别优势)。如果您要放入向量中的内容是字符串,大多数只包含指针和一些"簿记"字段(分配内存的数量,当前使用的内存量),那么这将是几乎与传递引用一样高效,因为移动只需执行浅拷贝——仅复制指针和簿记值本身,而不是所有数据它指向的数据。然而,如果所涉及的对象直接持有所有数据(即不是指针),那么移动速度将与复制一样慢。
通过引用传递,避免了所有这些复制,因此即使对于像字符串这样的东西,它仍然通常更快(在原始对象不会失效的情况下)。它还具有与C++98/03一起使用的微小优势,而不仅仅是C++11。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接