Visual Studio 2010下C++/STL列表push_back对象数据部分未初始化问题
问题分析与解决方法
这个问题是Visual Studio 2010编译器的一个已知行为——当你没有为结构体Foo显式定义复制构造函数时,编译器自动生成的默认复制构造函数在处理list::push_back临时对象的复制操作时,没有正确复制所有成员变量,导致y成员保留了未初始化的内存值(你看到的-33686019就是未初始化栈内存的典型垃圾值)。
为什么会出现这种差异?
当你调用foolist.push_back(Foo(x, x*x))时,流程是这样的:
- 创建临时
Foo对象(构造函数输出的就是这个临时对象); - 调用复制构造函数,把临时对象的内容复制到list内部分配的新
Foo对象中; - 临时对象被销毁。
GCC的自动生成默认复制构造函数会严格执行逐成员复制,所以x和y都能正确被拷贝;但VS2010的自动生成复制构造函数在这个场景下出现了异常,只复制了第一个成员x,y完全没被处理,最终list里的对象y就是未初始化的状态。
解决方法:显式定义复制构造函数
只需要为Foo结构体添加一个显式的复制构造函数,手动复制所有成员变量,就能彻底解决这个问题。修改后的代码如下:
#include <map> #include <list> #include <iostream> using namespace std ; struct Foo { Foo ( int x , int y ) ; // 显式定义复制构造函数,确保所有成员被正确复制 Foo(const Foo& other) : x(other.x), y(other.y) { cout << "copy construct " << *this << endl ; } friend ostream & operator<< ( ostream & out , const Foo & foo ) ; int x,y ; }; Foo::Foo ( int x , int y ) : x(x),y(y) { cout << "construct " << *this << endl ; } ostream & operator<< ( ostream & out , const Foo & foo ) { out << "Foo( " << foo.x << "," << foo.y << " )[" << &foo << "]"; return out ; } int main () { list<Foo> foolist ; for ( int x = 7 ; x < 12 ; x++ ) foolist.push_back( Foo( x,x*x )) ; for ( list<Foo>::iterator i = foolist.begin() ; i != foolist.end() ; ++i ) cout << *i << endl ; }
验证效果
修改后在VS2010中运行,输出会和GCC完全一致:每个list中的对象y都会正确复制临时对象的值,不会再出现未初始化的垃圾值。同时你会看到新增的复制构造函数输出,能直观确认复制过程正常执行。
补充说明:这个问题是VS2010特有的bug,在VS2012及以后的版本中已经被修复。如果条件允许,升级编译器版本也是一个一劳永逸的解决方案。
内容的提问来源于stack exchange,提问作者Captain'Flam
相关产品推荐
相关产品推荐

