实例化C++类时结构体重复占用同内存地址问题排查求助
问题排查:Signal类结构体指针地址重复与数据覆盖问题
问题描述
我有一个signal类,每次实例化时本应创建独立的结构体成员。实例本身和sigName成员都在独立内存空间,但构造函数中创建的结构体每次都被分配相同内存地址,导致之前实例的结构体数据被覆盖。指针和结构体均未声明为static,无法理解该现象成因,恳请排查代码错误。
原代码
signal.h
#pragma once struct GenParams { float a; float b; }; class signal { public: signal(); ~signal(); std::string sigName; GenParams* mGP; // 未声明static,理论上每个实例应有独立的mGP,设为private也无变化 };
signal.cpp
#include "signal.h" signal::signal() { GenParams GP; // 本应每个实例有独立的GP,但实际每次都分配同一内存地址 mGP = &GP; // mGP每次构造都指向同一地址 // 填充默认值 GP.a = 0.0; GP.b = 5.0; } signal::~signal() { }
interface.h
#include "signal.h" class interface { public: interface(); ~interface(); std::string interName; std::vector<signal*> sigList; interface* iPtr; unsigned int sigNum; void newSignal(); };
interface.cpp
#include "interface.h" #include <string> interface::interface() : iPtr(this) { sigNum = 0;} interface::~interface() { for (auto i : sigList) delete i; } void interface::newSignal() { signal* s = new signal; // 这行执行完后,结构体内存值还正确 // 这行未引用结构体或signal,但结构体内存被释放,值消失 std::string newSName = this->interName + "sig" + std::to_string(sigNum + 1); // 结构体出现无效值 s->sigName = newSName; sigList.push_back(s); // 实例的sigName正确,但所有实例的mGP都指向同一内存地址 sigNum++; }
错误原因分析
- 局部变量生命周期失效导致悬空指针
在signal构造函数中,GenParams GP;是栈上的局部变量,它的生命周期仅存在于构造函数执行期间。构造函数执行完毕后,该局部变量会被销毁,对应的栈内存被释放。但你让mGP指向了这块已失效的内存,这就是典型的悬空指针问题。 - 重复地址的成因
每次调用signal构造函数时,程序会在栈上为局部变量GP分配固定位置的空间(栈帧结构固定)。当构造函数执行完,栈空间被回收,下次调用构造函数时,这块空间会被再次分配,所以每次GP的地址都相同。所有signal实例的mGP都指向同一块失效的栈内存,后续任何栈操作(比如创建std::string)都会覆盖这块内存的数据,导致之前实例的结构体数据被破坏。
修复方案
方案1:将GenParams设为类成员(推荐)
直接把GenParams作为signal的成员变量,无需指针,每个实例会自动拥有独立的结构体实例,内存由对象管理,无生命周期问题:
修改signal.h:
#pragma once struct GenParams { float a; float b; }; class signal { public: signal(); ~signal(); std::string sigName; GenParams mGP; // 改为成员变量,而非指针 };
修改signal.cpp:
#include "signal.h" signal::signal() { // 直接初始化成员变量 mGP.a = 0.0; mGP.b = 5.0; } signal::~signal() { }
方案2:动态分配内存(需手动管理)
如果必须使用指针,在构造函数中用new分配堆内存,确保内存生命周期可控,同时在析构函数中释放内存避免泄漏:
修改signal.cpp:
#include "signal.h" signal::signal() { mGP = new GenParams(); // 堆上分配内存 // 初始化值 mGP->a = 0.0; mGP->b = 5.0; } signal::~signal() { delete mGP; // 释放堆内存 }
内容的提问来源于stack exchange,提问作者MacLCM
相关产品推荐
相关产品推荐

