You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实例化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 04:24:25