向函数传递类对象数组后无法获取settingUp设置的预期值
向函数传递对象数组后,在main中调用printValues无法获取settingUp函数里设置的预期值——settingUp内部调用printValues能输出正确结果,但main中访问array[0]->length看似正常,访问array[2]->length直接失败。
问题出在settingUp函数里的arrayPrueba变量:
const dataClass * arrayPrueba[3];
这是一个栈上的局部数组,当settingUp函数执行完毕后,栈帧会被销毁,arrayPrueba占用的内存会被系统回收或覆盖。而你在statusClass::setValues里把这个局部数组的地址赋值给了array成员,导致statusClass里保存的是一个悬空指针。
函数退出后,访问这个悬空指针指向的内存属于未定义行为:有时候array[0]的内存还没被覆盖,能读出值;但array[2]的内存已经被其他数据覆盖,就会出现读取失败甚至程序崩溃的情况。
另外代码里还有一个编译错误:prueba0是dataClass*类型的指针,调用成员函数应该用->而非.,正确写法是prueba0->setValues(1);,否则无法通过编译。
以下是几种可行的修复方式,按推荐程度排序:
1. 使用std::vector管理数组(最推荐)
修改statusClass的成员,把裸指针数组换成std::vector<const dataClass*>,让容器自动管理内存:
// statusClass.h 中修改成员 #include <vector> class statusClass { private: uint8_t newStatusSelectorByte; std::vector<const dataClass*> array; // 替换原来的 const dataClass** array; public: void setValues(uint8_t _statusSelectorByte, const dataClass** _array, size_t arraySize); void printValues(); };
// statusClass.cpp 实现 void statusClass::setValues(uint8_t _statusSelectorByte, const dataClass** _array, size_t arraySize){ newStatusSelectorByte = _statusSelectorByte; array.clear(); for (size_t i = 0; i < arraySize; ++i) { array.push_back(_array[i]); } }; void statusClass::printValues(){ printf("TP: statusClass -> printValues: Prueba = %d\n", newStatusSelectorByte); if (array.size() > 1) { printf("TP: statusClass -> printValues: arrayPrueba = %d\n", array[1]->length); } }
然后在settingUp里调用时传入数组大小:
void settingUp(statusClass *_status){ dataClass * prueba0 = new dataClass(); dataClass * prueba1 = new dataClass(); dataClass * prueba2 = new dataClass(); const dataClass * arrayPrueba[3]; prueba0->setValues(1); // 修正为->调用 prueba1->setValues(2); prueba2->setValues(3); arrayPrueba[0] = prueba0; arrayPrueba[1] = prueba1; arrayPrueba[2] = prueba2; _status[1].setValues(1, arrayPrueba, 3); // 传入数组大小 _status[0].printValues(); }
这种方式不需要手动管理内存,避免悬空指针和内存泄漏风险。
2. 堆分配数组
把arrayPrueba改成堆上分配的数组,这样函数结束后内存不会被释放:
void settingUp(statusClass *_status){ dataClass * prueba0 = new dataClass(); dataClass * prueba1 = new dataClass(); dataClass * prueba2 = new dataClass(); // 堆分配数组 const dataClass **arrayPrueba = new const dataClass*[3]; prueba0->setValues(1); prueba1->setValues(2); prueba2->setValues(3); arrayPrueba[0] = prueba0; arrayPrueba[1] = prueba1; arrayPrueba[2] = prueba2; _status[1].setValues(1, arrayPrueba); _status[0].printValues(); }
⚠️ 注意:这种方式需要后续手动释放arrayPrueba和prueba0等堆内存,否则会造成内存泄漏。比如在statusClass的析构函数里添加:
statusClass::~statusClass(){ delete[] array; // 释放堆数组 // 若statusClass负责管理dataClass对象,还要释放每个元素 for (size_t i = 0; i < 3; ++i) { delete array[i]; } }
3. 使用静态数组(不推荐)
把arrayPrueba声明为静态数组,使其生命周期和程序一致:
void settingUp(statusClass *_status){ dataClass * prueba0 = new dataClass(); dataClass * prueba1 = new dataClass(); dataClass * prueba2 = new dataClass(); static const dataClass * arrayPrueba[3]; // 添加static prueba0->setValues(1); prueba1->setValues(2); prueba2->setValues(3); arrayPrueba[0] = prueba0; arrayPrueba[1] = prueba1; arrayPrueba[2] = prueba2; _status[1].setValues(1, arrayPrueba); _status[0].printValues(); }
这种方式虽然能解决问题,但静态数组是全局共享的,多次调用settingUp会覆盖之前的值,存在线程安全问题,不建议在多线程或需要复用的场景使用。
内容的提问来源于stack exchange,提问作者David Moreno García

