构造函数指针赋值正常,外部调用时指针数据异常求助
问题分析:StateSystem类中指针A的数据异常问题
问题背景
现有一个StateSystem类,其构造函数负责从npz文件导入数据到double类型指针A中,构造函数代码如下:
StateSystem::StateSystem(std::string filename) { cnpy::NpyArray A_npy = cnpy::npz_load(filename, "A"); StateSystem::A = (double *)mkl_malloc(A_npy.shape[0] * A_npy.shape[1] * sizeof(double), 64); this->StateSystem::A = A_npy.data<double>(); std::cout << "A (in constructor):" << std::endl; for (size_t i = 0; i < StateSystem::n; i++) { for (size_t j = 0; j < StateSystem::n; j++) { std::cout << " " << StateSystem::A[j + StateSystem::n * i] << " "; } std::cout << std::endl; } }
用包含单位矩阵的npz文件测试时,构造函数内的打印输出正常:
A (in constructor): 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1
但调用类的info方法打印该变量时,数据出现异常,info方法代码如下:
void StateSystem::info() { std::cout << UNDERLINE << "State system: n=" << StateSystem::n << " m=" << StateSystem::m << " p=" << StateSystem::p << CLOSEUNDERLINE << std::endl; std::cout << "A:" << std::endl; for (size_t i = 0; i < StateSystem::n; i++) { for (size_t j = 0; j < StateSystem::n; j++) { std::cout << " " << StateSystem::A[j + StateSystem::n * i] << " "; } std::cout << std::endl; }
调用后输出结果:
State system: n=4 m=1 p=1 A: 1.13825e-313 -1.74758e+260 0 0 0 1 0 0 0 0 1 0 0 0 0 1
原因解析
- 野指针问题:构造函数中,
A_npy是局部变量,cnpy::NpyArray的data()返回的是其内部缓冲区的指针。当构造函数执行完毕,A_npy会被销毁,它的内部缓冲区也会被释放。但你把这个内部指针赋值给了StateSystem::A,导致构造函数结束后StateSystem::A变成野指针,指向已经被释放的内存区域。 - 构造函数内打印正常的原因:构造函数运行时,
A_npy还未被销毁,内部缓冲区依然有效,所以此时打印的数据是正确的;但info方法调用时,A_npy早已销毁,访问野指针指向的内存就会读出随机垃圾值(也就是输出中第一行的异常数值)。 - 额外内存泄漏:你先用
mkl_malloc分配了内存给StateSystem::A,但紧接着就用A_npy.data()的指针覆盖了它,导致刚分配的内存无人管理,直接泄漏。
修复方案
方案一:复制数据到自有内存
自己分配内存后,把A_npy的数据复制进去,确保内存所有权属于StateSystem类:
StateSystem::StateSystem(std::string filename) { cnpy::NpyArray A_npy = cnpy::npz_load(filename, "A"); size_t total_elements = A_npy.shape[0] * A_npy.shape[1]; // 分配内存 StateSystem::A = (double *)mkl_malloc(total_elements * sizeof(double), 64); // 复制数据到自有内存 std::memcpy(StateSystem::A, A_npy.data<double>(), total_elements * sizeof(double)); // 后续打印代码... }
同时要在类的析构函数中添加mkl_free(StateSystem::A);,避免内存泄漏。
方案二:保留NpyArray作为类成员
把A_npy声明为StateSystem的成员变量,让它的生命周期和类实例一致,这样内部缓冲区不会提前释放:
// 类声明中添加成员 class StateSystem { private: cnpy::NpyArray A_npy; double* A; // 其他成员... }; // 构造函数修改 StateSystem::StateSystem(std::string filename) { A_npy = cnpy::npz_load(filename, "A"); StateSystem::A = A_npy.data<double>(); // 后续打印代码... }
这种方式不需要手动管理内存,A_npy会在类实例销毁时自动释放内部缓冲区。
内容的提问来源于stack exchange,提问作者Metersquared
相关产品推荐
相关产品推荐

