C++自定义类含指针成员存入数组后访问崩溃的原因与解决方案
问题原因
你遇到的崩溃是野指针解引用触发的内存访问违规:
- 当类成员是普通
int类型时,未初始化的int存储的是栈上的随机垃圾值,直接读取虽然属于未定义行为,但通常不会触发内存访问异常,仅会得到错误的数值,所以程序可以正常退出。 - 当类成员改为
int*指针类型时,编译器生成的默认构造函数不会初始化该指针,指针会成为指向随机内存地址的野指针,调用getint()时执行*p解引用操作,相当于访问没有权限的非法内存地址,直接触发段错误,对应你看到的退出码3221225477(Windows平台下的访问违例退出码)。
可行实现方案
方案1:手动管理原生指针,遵守三五法则
如果你必须使用原生指针,需要主动实现构造函数初始化指针,同时补充析构、拷贝构造、拷贝赋值运算符(C++11及以上还可以补充移动构造、移动赋值),避免内存泄漏、重复释放、野指针问题:
#include <iostream> class A { int* p; public: // 构造函数:初始化指针,分配内存 A() : p(new int(0)) {} // 析构函数:释放内存 ~A() { delete p; } // 拷贝构造:深拷贝 A(const A& other) : p(new int(*other.p)) {} // 拷贝赋值:深拷贝 A& operator=(const A& other) { if (this != &other) { *p = *other.p; } return *this; } void setint(int p_x); int getint(); }; void A::setint(int p_x) {*p = p_x;} int A::getint() {return *p;} int main() { A arr_a[5]; std::cout << arr_a[0].getint() << std::endl; // 输出初始值0 arr_a[0].setint(10); std::cout << arr_a[0].getint() << std::endl; // 输出10 return 0; }
方案2:使用智能指针自动管理内存(更推荐)
C++11及以上版本可以用标准库的智能指针替代原生指针,不需要手动管理内存,也不需要手动实现析构、拷贝等特殊成员函数,编译器生成的默认函数即可满足需求:
#include <iostream> #include <memory> // 智能指针头文件 class A { std::unique_ptr<int> p; public: // 构造函数初始化智能指针 A() : p(std::make_unique<int>(0)) {} void setint(int p_x); int getint(); }; void A::setint(int p_x) {*p = p_x;} int A::getint() {return *p;} int main() { A arr_a[5]; std::cout << arr_a[0].getint() << std::endl; arr_a[0].setint(20); std::cout << arr_a[0].getint() << std::endl; return 0; }
如果需要支持A实例的拷贝操作,可以将std::unique_ptr替换为std::shared_ptr。
方案3:指针指向外部已存在的合法int对象
如果指针不需要持有动态分配的内存,也可以让指针指向生命周期长于A实例的外部int对象,注意要避免指针悬空:
#include <iostream> class A { int* p; public: // 构造函数传入外部int的地址 explicit A(int* external_p) : p(external_p) {} void setint(int p_x); int getint(); }; void A::setint(int p_x) {*p = p_x;} int A::getint() {return *p;} int main() { int val_arr[5] = {0}; // 外部int数组,生命周期和A数组一致 A arr_a[5] = {A(&val_arr[0]), A(&val_arr[1]), A(&val_arr[2]), A(&val_arr[3]), A(&val_arr[4])}; std::cout << arr_a[0].getint() << std::endl; arr_a[0].setint(30); std::cout << arr_a[0].getint() << std::endl; return 0; }
内容的提问来源于stack exchange,提问作者celphato
相关产品推荐
相关产品推荐

