VS2010 C++中静态类对象指针数组初始化后失效的原因?
问题分析:静态对象指针数组初始化后变为未初始化存储
问题场景
使用VS 2010 Pro C++开发,定义Protocol_element类及显式构造函数,声明静态的该类对象指针数组并通过临时对象初始化。调试时可见数组构造完成,但在main函数中断点查看,数组变为未初始化存储。
相关代码:
class Protocol_element { public: const char *Argument; int EnumID; int TrueEnum; int FalseEnum; bool IsEnabled; // 省略其他成员 }; // 显式构造函数 Protocol_element(const char * arg, int id, int tru, int fals, bool isEnab) { Argument = arg; EnumID = id; TrueEnum = tru; FalseEnum = fals; IsEnabled = isEnab; } // 静态数组定义 Protocol_element *Parms::Protocol[] = { &Protocol_element("SSLV2", GSK_PROTOCOL_SSLV2, GSK_PROTOCOL_SSLV2_ON, GSK_PROTOCOL_SSLV2_OFF, true), &Protocol_element("SSLV3", GSK_PROTOCOL_SSLV3, GSK_PROTOCOL_SSLV3_ON, GSK_PROTOCOL_SSLV3_OFF, true), &Protocol_element("TLSV1", GSK_PROTOCOL_TLSV1, GSK_PROTOCOL_TLSV1_ON, GSK_PROTOCOL_TLSV1_OFF, true), &Protocol_element("TLSV1.1", GSK_PROTOCOL_TLSV1_1, GSK_PROTOCOL_TLSV1_1_ON, GSK_PROTOCOL_TLSV1_1_OFF, false), &Protocol_element("TLSV1.2", GSK_PROTOCOL_TLSV1_2, GSK_PROTOCOL_TLSV1_2_ON, GSK_PROTOCOL_TLSV1_2_OFF, false), &Protocol_element("TLSV1.3", GSK_PROTOCOL_TLSV1_3, GSK_PROTOCOL_TLSV1_3_ON, GSK_PROTOCOL_TLSV1_3_OFF, false), nullptr };
原因解析
问题的核心在于你取了临时对象的地址存入数组:
- 当你写
&Protocol_element(...)时,这里创建的是一个临时Protocol_element对象,它的生命周期仅限于当前初始化表达式——也就是数组元素初始化完成后,这个临时对象就会被销毁,内存被释放。 - 数组里存储的指针此时就变成了悬空指针,指向已经被回收的内存空间。调试时看到的"数组构造完成"只是临时对象还没销毁的瞬间,等到进入
main函数,临时对象早已不存在,指针指向的就是未初始化的垃圾存储。
解决方案
有几种可行的修正方式,根据你的需求选择:
1. 使用静态对象初始化数组
为每个元素创建静态对象,确保其生命周期贯穿整个程序运行期:
// 先定义静态对象 static Protocol_element sslv2("SSLV2", GSK_PROTOCOL_SSLV2, GSK_PROTOCOL_SSLV2_ON, GSK_PROTOCOL_SSLV2_OFF, true); static Protocol_element sslv3("SSLV3", GSK_PROTOCOL_SSLV3, GSK_PROTOCOL_SSLV3_ON, GSK_PROTOCOL_SSLV3_OFF, true); static Protocol_element tlsv1("TLSV1", GSK_PROTOCOL_TLSV1, GSK_PROTOCOL_TLSV1_ON, GSK_PROTOCOL_TLSV1_OFF, true); static Protocol_element tlsv1_1("TLSV1.1", GSK_PROTOCOL_TLSV1_1, GSK_PROTOCOL_TLSV1_1_ON, GSK_PROTOCOL_TLSV1_1_OFF, false); static Protocol_element tlsv1_2("TLSV1.2", GSK_PROTOCOL_TLSV1_2, GSK_PROTOCOL_TLSV1_2_ON, GSK_PROTOCOL_TLSV1_2_OFF, false); static Protocol_element tlsv1_3("TLSV1.3", GSK_PROTOCOL_TLSV1_3, GSK_PROTOCOL_TLSV1_3_ON, GSK_PROTOCOL_TLSV1_3_OFF, false); // 数组指向这些静态对象 Protocol_element *Parms::Protocol[] = { &sslv2, &sslv3, &tlsv1, &tlsv1_1, &tlsv1_2, &tlsv1_3, nullptr };
2. 直接使用对象数组而非指针数组
如果不需要指针语义,直接存储对象实例,避免指针悬空问题:
// 修改数组类型为对象数组 Protocol_element Parms::Protocol[] = { Protocol_element("SSLV2", GSK_PROTOCOL_SSLV2, GSK_PROTOCOL_SSLV2_ON, GSK_PROTOCOL_SSLV2_OFF, true), Protocol_element("SSLV3", GSK_PROTOCOL_SSLV3, GSK_PROTOCOL_SSLV3_ON, GSK_PROTOCOL_SSLV3_OFF, true), Protocol_element("TLSV1", GSK_PROTOCOL_TLSV1, GSK_PROTOCOL_TLSV1_ON, GSK_PROTOCOL_TLSV1_OFF, true), Protocol_element("TLSV1.1", GSK_PROTOCOL_TLSV1_1, GSK_PROTOCOL_TLSV1_1_ON, GSK_PROTOCOL_TLSV1_1_OFF, false), Protocol_element("TLSV1.2", GSK_PROTOCOL_TLSV1_2, GSK_PROTOCOL_TLSV1_2_ON, GSK_PROTOCOL_TLSV1_2_OFF, false), Protocol_element("TLSV1.3", GSK_PROTOCOL_TLSV1_3, GSK_PROTOCOL_TLSV1_3_ON, GSK_PROTOCOL_TLSV1_3_OFF, false) // 可通过数组长度或添加特殊标记判断结束 };
3. 动态分配对象(需注意内存管理)
如果必须用指针数组,可以通过new动态分配对象,确保内存不会被自动回收,但要记得在程序结束时手动释放:
Protocol_element *Parms::Protocol[] = { new Protocol_element("SSLV2", GSK_PROTOCOL_SSLV2, GSK_PROTOCOL_SSLV2_ON, GSK_PROTOCOL_SSLV2_OFF, true), new Protocol_element("SSLV3", GSK_PROTOCOL_SSLV3, GSK_PROTOCOL_SSLV3_ON, GSK_PROTOCOL_SSLV3_OFF, true), new Protocol_element("TLSV1", GSK_PROTOCOL_TLSV1, GSK_PROTOCOL_TLSV1_ON, GSK_PROTOCOL_TLSV1_OFF, true), new Protocol_element("TLSV1.1", GSK_PROTOCOL_TLSV1_1, GSK_PROTOCOL_TLSV1_1_ON, GSK_PROTOCOL_TLSV1_1_OFF, false), new Protocol_element("TLSV1.2", GSK_PROTOCOL_TLSV1_2, GSK_PROTOCOL_TLSV1_2_ON, GSK_PROTOCOL_TLSV1_2_OFF, false), new Protocol_element("TLSV1.3", GSK_PROTOCOL_TLSV1_3, GSK_PROTOCOL_TLSV1_3_ON, GSK_PROTOCOL_TLSV1_3_OFF, false), nullptr }; // 在程序退出前释放内存 void cleanup() { for (int i = 0; Parms::Protocol[i] != nullptr; ++i) { delete Parms::Protocol[i]; Parms::Protocol[i] = nullptr; } }
内容的提问来源于stack exchange,提问作者Charles
相关产品推荐
相关产品推荐

