【发布时间】:2012-07-25 15:22:05
【问题描述】:
将此代码放入MS Visual C++ 2010,编译(调试或发布),insert()循环会崩溃,push_back循环不会:
#include <vector>
#include <string>
using std::vector;
using std::string;
int main()
{
vector<string> vec1;
vec1.push_back("hello");
for (int i = 0; i != 10; ++i)
vec1.push_back( vec1[0] );
vector<string> vec2;
vec2.push_back("hello");
for (int i = 0; i != 10; ++i)
vec2.insert( vec2.end(), vec2[0] );
return 0;
}
问题是 push_back() 和 insert() 都通过引用获取新项目, 并且当向量被重新分配以获得更多空间时,新项目在插入之前会失效。
GCC 应该也有这个问题。我没有检查 Clang,但这取决于它使用的是哪个 STD 库。
MSVC2010 在 push_back() 中有一些额外的代码,用于检测新项目是否实际上是向量中的项目。如果是这样,它会记录项目的索引,并在分配内存后使用该索引插入项目(而不是使用现在无效的引用)——使用 _Inside(_STD addressof(_Val))
MSVC 的额外代码是非标准的吗?
我担心的是我不确定我可能在什么代码中做了类似 vec.push_back(vec[1]);或 vec.insert(it, vec[2]); 我必须查看数百行甚至数千行使用 push_back 和 insert 的代码,这只是我自己的代码...... 3rd 方库也可能受到影响。
我假设使用这种技术可以使 GCC 以可怕的方式死掉(我没有看到额外的代码来处理这种情况,但 valgrind 在我的简单示例中没有检测到它,因此更难测试),
如何最好地发现和避免犯这个错误?
MSVC2010 的额外 push_back() 代码是否非标准?当 MSVC 发现以这种方式使用的向量时,是否应该改为检测并断言? (即安全计算计划)
我正在考虑破解 MSVC2010 和 GCC 的标头来检测这些情况。
还有其他想法吗?
谢谢, 保罗
PS:另请注意,如果您可以保证向量不需要调整大小,则此用法非常好(且有效)
【问题讨论】:
-
代码在 g++ 4.6 下运行良好。 Valgrind 也没有发现任何问题。
-
在 MSVC 2012 RC 下工作正常。
-
我刚刚发现了这个确切的错误,已在 MSVC 2011 和 2012 中修复:connect.microsoft.com/VisualStudio/feedback/details/735732
-
我认为“破解 MSVC2010 和 GCC 的标头来检测这些情况”是一个糟糕的主意。如果您的代码库确实有“数百行甚至数千行使用 push_back 和 insert 的代码”,那么您很可能是团队的一员,其他人不会看到您的 hack,因为它是标准库的一部分,而不是您自己的代码。此外,编译器更新可能会使您的更改消失。 +1 链接到 MS 错误。
-
我最终破解了标头(首先检测,如果需要,稍后修复),因为它只需要 MSVC 2010,所以我只需要检测并解决在 MSVC 2012 之前使用它的情况. 理想情况下,MS 会针对此类错误发布补丁。另外,我可以记录黑客攻击。它在一个复杂的编译环境中,所以已经有一个很长的过程来编译所有需要的库。
标签: c++ visual-studio-2010 vector