2011-01-11 59 views
5

我能想到的填充std::vector在填充载体

假设的三种不同的方式,我们有

vector<int> v(100, 0); 

然后,我希望它保持(1,1,1)。我们可以这样做:

v.clear(); 
v.resize(3, 1); 

或者

v = vector<int>(3, 1); 

而且我知道另一种方法:

vector<int>(3, 1).swap(v); 

首先的问题是:任何人的最好的方法?

第二个问题:假设v被声明在主函数之外。根据这answer,内存将被分配在数据段中。如果我使用第二种或第三种方法,内存是否会分配到堆栈上?

+4

这是不正确的。无论在哪里声明,原始数组都会分配它们的内存。 `vector`将始终堆分配。 int []!=向量。 – Puppy 2011-01-11 19:30:39

回答

3

所以,这里的差异,我会让你决定什么是最适合你的情况。

v.clear(); 
v.resize(3, 1); 

在这种情况下,我们已经将矢量标记为清除。为了容纳100个元素(它可以超过100个元素所需的空间),它仍然拥有它分配的任何东西。然后我们添加了3个值为1的项目。所有这些都是增加大小计数器并重置3个值,底层内存仍然是相同的大小。

v = vector<int>(3, 1); 

这确实非常不同之处在于创建的临时额外的载体,同样的事情,而不是有被间歇性的地方计数器为0,然后用一些值3,简单复制计数器大小,然后再执行一个类似于memcpy的操作来复制3个元素。为v分配的底层内存大小仍足以容纳100个整数。

vector<int>(3, 1).swap(v); 

这一个是显着不同的。在这种情况下,我们创建一个临时向量,它包含3个元素,它们都被初始化为1.理论上,它仍然可以为100个元素保留足够的内存,但机会很少。然后我们将这个向量与我们自己的交换,让临时被破坏。这有额外的好处,清除我们的旧矢量分配的任何额外内存不在临时。这样做的方式是两个向量(我们的v和临时的)交换的不仅仅是计数器和值,它们还交换缓冲区指针。

这是收缩矢量的唯一方法。

2

要首先回答第二个问题:vector将始终为其包含的对象动态分配内存,因此它将最终堆在堆上。

至于哪种重新分配方法更好,我会说你的第一或第二种方法使你的意图最清楚,这是最重要的属性。

9

您如何使用该任务的矢量成员?

std::vector<int> v(100); 
v.assign(3, 1); // this is what you should do. 
+0

忽略这些显而易见的事情是多么容易。 – 2011-01-11 19:41:24

+1

它是v.clear()的缩写版本; v.resize(3,1);`具有相同的异常安全问题。 – 2011-01-11 20:05:21

1

交换将有效地将矢量缩小为3个元素。其他人可能不会。

vector<int> v(100); 
v.assign(3, 1); 
assert(v.size() == 3); 
assert(v.capacity() != 3); 

v = vector<int>(3, 1); 
// Now, v.capacity() is likely not to be 3. 

vector<int>(3, 1).swap(v); 
assert(v.capacity() == 3); 

其他方法不会在内部调整矢量大小。即使size()成员返回3,它仍将在内存中占用100 * sizeof(int)个字节。尝试显示v.capacity()以说服自己。

+0

差不多。我们不知道这些情况下所占用的尺寸究竟是多少。许多向量实现预留额外的空间,以便频繁插入不会单独导致重新分配和移动。 – 2011-01-11 19:47:16

1

在前面的文章中没有提到的一个问题在选择这些替代方案时非常重要。即异常安全。 vector<int>(3, 1).swap(v);有很强的例外安全保证。表格v = vector<int>(3, 1);也可以提供这种保证,如果分配实施交换。第一个选择是不安全的:v.clear(); v.resize(3, 1);