在C ++ Primer中发现以下语句
由于向量有效增长,因此通常是不必要的,并且可以 导致性能较差-定义特定大小的向量。 此规则的例外情况是,如果所有元素实际上都需要 相同的值。如果需要不同的元素值,通常会更大 定义空向量并将元素添加为值的效率很高 需要在运行时知道。
我对此有疑问,如果您事先保留了内存,那么就不需要重新分配(这被认为是一个较慢的过程)。那么如何使用push_back带来更好的性能呢?
答案 0 :(得分:4)
我认为作者正在比较以下两种情况:
int n = ...;
std::vector<...> v(n);
for (auto& x : v) x = some_value_known_at_runtime;
和
int n = ...;
std::vector<...> v;
for (int i = 0; i < n; i++) v.push_back(some_value_known_at_runtime);
第一种情况是使用vector
默认构造的元素构造n
,然后再分配它们;这可能会导致性能下降。
当然,您可以在第二种情况下使用reserve
,这样可以避免重新分配并提高效率;如果可以提前知道元素的数量。
int n = ...;
std::vector<...> v;
v.reserve(n);
for (int i = 0; i < n; i++) v.push_back(some_value_known_at_runtime);
答案 1 :(得分:1)
这取决于您在默认构造函数中所做的工作。如果您的对象在默认构造函数中做一些昂贵的事情,则您的程序可以在向量分配中冻结一会儿。相反,push_back将为每个对象一次并递增(或及时)调用副本构造函数。那可能更快。
但是,重新分配和批量复制可能也很昂贵,特别是如果您的对象是许多对象的组合,依此类推,那么在这种情况下,只有概要分析可以说出最好的方法。
另一方面,如果默认构造函数不执行任何操作,则在大多数情况下避免重新分配将是胜利。
答案 2 :(得分:1)
我在C ++入门中看到了这一说法,他在以下情况中如此说道。
// read words from the standard input and store them as elements in a vector
string word;
vector<string> text; // empty vector
while (cin >> word) {
text.push_back(word); // append word to text
}
这里的向量每次都以不同的值增长大小。
他还说的是“经常不必要”而不是“总是”。我对它进行了已知次数的测试,并且在所有情况下储备金的表现都更好。
请参阅下面的Vector实现代码片段,以便更好地理解。
template<typename T>
class Vector {
T∗ elem; // pointer to first element
T∗ space; // pointer to first unused (and uninitialized) slot
T∗ last; // pointer to last slot
public:
// …
int size(); // number of elements (space-elem)
int capacity(); // number of slots available for elements (last-elem)
// ...
void reserve(int newsz); // increase capacity() to newsz
// ...
void push_back(const T& t); // copy t into Vector
};
template<typename T>
void Vector<T>::push_back(const T& t) {
if (capacity()<size()+1) // make sure we have space for t
reserve(size()==0?8:2∗size()); // double the capacity
new(space){t}; // initialize *space to t
++space;
}
答案 3 :(得分:0)
没有什么要考虑的。
您是否经常使用一个和相同的向量,我的意思不是5或10次,而是数千次。原因是您想尽可能地重用该对象,以避免不必要的分配和释放。为此,您可以使用clear
向量有可能总是具有一定数量的元素,那么您可以使用reserve
命令预分配元素。
通常,如果您将向量作为永久存储,而很少更改内容,则不要理会这些内容。