11

I'm trying to insert a copy of an existing vector element to double it up. The following code worked in previous versions but fails in Visual Studio 2010.

#include <iostream>
#include <vector>

using namespace std;

int main(int argc, char* argv[])
{
   vector<int> test;
   test.push_back(1);
   test.push_back(2);
   test.insert(test.begin(), test[0]);
   cout << test[0] << " " << test[1] << " " << test[2] << endl;
   return 0;
}

Output is -17891602 1 2, expected 1 1 2.

I've figured out why it's happening - the vector is being reallocated, and the reference becomes invalid before it's copied to the insertion point. The older Visual Studio apparently did things in a different order, thus proving that one possible outcome of undefined behavior is to work correctly and also proving that it's never something you should rely on.

I've come up with two different ways to fix this problem. One is to use reserve to make sure that no reallocation takes place:

   test.reserve(test.size() + 1);
   test.insert(test.begin(), test[0]);

The other is to make a copy from the reference so that there's no dependency on the reference remaining valid:

template<typename T>
T make_copy(const T & original)
{
    return original;
}

   test.insert(test.begin(), make_copy(test[0]));

Although both work, neither one feels like a natural solution. Is there something I'm missing?

4

2 回答 2

4

问题在于vector::insert它将一个值的引用作为第二个参数而不是一个值。您不需要模板来制作副本,只需使用复制构造函数创建另一个对象,该对象将通过引用传递。即使调整了向量的大小,此副本仍然有效。

#include <iostream>
#include <vector>

using namespace std;

int main(int argc, char* argv[])
{
   vector<int> test;
   test.push_back(1);
   test.push_back(2);
   test.insert(test.begin(), int(test[0]));
   cout << test[0] << " " << test[1] << " " << test[2] << endl;
   return 0;
}
于 2012-04-20T04:08:16.083 回答
1

我相信这是定义的行为。在§23.2.32011 C++ 标准中,表 100 列出了序列容器要求,并且有一个针对这种情况的条目。它给出了示例表达式

a.insert(p,t)

其中a的值X是包含类型元素的序列容器类型Tp是 的常量迭代器a,并且t是类型的左值或常量右值X::value_type,即T

这个表达式的断言是:

要求: TCopyInsertableX。为vectordeque,T也应为CopyAssignable
效果:t插入before的副本p

我能找到的唯一相关矢量特定报价在§23.3.6.5第 1 段中:

备注:如果新大小大于旧容量,则导致重新分配。如果没有发生重新分配,则插入点之前的所有迭代器和引用仍然有效。

insert尽管这确实提到了重新分配的向量,但它并没有对先前对序列容器的要求做出例外。

至于解决这个问题,我同意@EdChum 的建议,即只制作元素的副本并插入该副本。

于 2012-04-19T00:30:33.000 回答