C++多态调用函数时_vfptr为空(0xcccccccccccccccc)问题求助
兄弟,你这问题我太熟了——本质就是悬空指针在搞鬼!咱们一步步拆解:
问题根源:局部对象销毁导致悬空指针
先看你TestApp::Init()里的这段代码:
void TestApp::Init() { RenderModels m(/* 参数省略 */); o.push_back(&m); // ... }
这里的RenderModels m是栈上的局部变量,当Init()函数执行完退出时,栈上的局部变量会被系统自动销毁,内存被释放。但你把它的地址&m塞进了std::vector<Object*> o里,等后续OnRender()调用这个指针时,它指向的是已经被回收的内存——这就是典型的悬空指针。
VS调试器里显示的_vfptr = 0xcccccccccccccccc,还有成员变量c、b值乱变,都是VS在告诉你:这块内存已经不属于你的对象了,是无效内存。
解决方案:让对象生命周期足够长
要解决这个问题,你得确保RenderModels对象的生命周期能覆盖到OnRender()的调用时机,有两种常用方式:
1. 用动态分配(new)创建堆对象
把局部对象改成堆上分配,这样对象不会随函数结束而销毁:
void TestApp::Init() { // 先把设备和上下文指针提出来,代码更清晰 auto device = Armageddon::Application::GetInstance()->GetWindow()->GetWindowGraphics()->GetComptrDevice(); auto device_context = Armageddon::Application::GetInstance()->GetWindow()->GetWindowGraphics()->GetComptrDeviceContext(); // 用new在堆上创建对象 RenderModels* m = new RenderModels(device, device_context); o.push_back(m); Armageddon::Log::GetLogger()->trace("NAME : {0}", o[0]->GetName()); }
⚠️ 注意:堆对象需要手动释放,记得在TestApp的析构函数里清理,避免内存泄漏:
TestApp::~TestApp() { for (auto obj : o) { delete obj; } o.clear(); }
2. 用智能指针(更推荐,自动管理内存)
手动管理堆内存容易忘释放,推荐用C++的智能指针std::unique_ptr或std::shared_ptr,它会自动帮你释放对象:
首先修改TestApp的成员变量类型:
private: ImVec2 CurrentWindowSize; // 把普通指针改成unique_ptr的vector std::vector<std::unique_ptr<Object>> o;
然后修改Init()函数:
void TestApp::Init() { auto device = Armageddon::Application::GetInstance()->GetWindow()->GetWindowGraphics()->GetComptrDevice(); auto device_context = Armageddon::Application::GetInstance()->GetWindow()->GetWindowGraphics()->GetComptrDeviceContext(); // 用make_unique创建智能指针 auto m = std::make_unique<RenderModels>(device, device_context); // 转移所有权到vector里 o.push_back(std::move(m)); Armageddon::Log::GetLogger()->trace("NAME : {0}", o[0]->GetName()); }
这样就不用手动写delete了,当TestApp销毁时,vector里的智能指针会自动释放对应的对象内存,省心又安全。
额外提醒:RenderModels里的引用成员要注意
另外,你的RenderModels类里有两个引用类型的成员:
private: Microsoft::WRL::ComPtr <ID3D11Device>& device; Microsoft::WRL::ComPtr <ID3D11DeviceContext>& device_context;
要确保你传入的ComPtr对象生命周期比RenderModels长,不然也会出现悬空引用的问题。不过目前你的核心问题是悬空指针,先解决这个再说。
内容的提问来源于stack exchange,提问作者Alexis

