VS2019与GCC下main函数作用域结束时触发Access violation问题修复
问题分析与解决方案
崩溃原因
你的代码崩溃根源在于返回值优化(RVO)的编译器实现差异,以及SimpleStructMng缺乏正确的拷贝/移动语义:
- 在MSVC 2019和GCC中,
CreateStruct函数返回ret时RVO未生效,编译器会先拷贝ret到返回值对象,随后销毁原ret。此时ret.mem作为std::shared_ptr的唯一引用,析构会触发MemHolder::~MemHolder,进而delete params.intPointer——而返回值对象的intPointer是从ret拷贝来的同一块内存地址,导致返回的objMng持有已被释放的野指针,后续访问触发内存错误。 - MSVC 2022中RVO生效,编译器直接在返回值的内存位置构造
ret,原ret不会被提前销毁,mem的引用计数保持为1,直到main结束才正常析构。
修改方案
方案1:添加移动语义并禁用拷贝
通过让SimpleStructMng支持移动构造,避免返回时的拷贝操作,确保mem的所有权被转移到返回值,原ret的mem被置空,析构时不会触发MemHolder销毁:
#include <iostream> #include <string> #include <memory> struct SimpleStructBase { int* intPointer; }; struct MemHolder { SimpleStructBase& params; MemHolder(SimpleStructBase& dist) : params(dist) { params.intPointer = new int(*dist.intPointer); } ~MemHolder() { delete params.intPointer; params.intPointer = nullptr; // 置空避免野指针残留 } }; struct SimpleStructMng : SimpleStructBase { protected: SimpleStructMng(SimpleStructBase& params) : SimpleStructBase(params) {} std::shared_ptr<MemHolder> mem; public: ~SimpleStructMng() = default; // 禁用拷贝构造与赋值,避免资源冲突 SimpleStructMng(const SimpleStructMng&) = delete; SimpleStructMng& operator=(const SimpleStructMng&) = delete; // 启用移动构造与赋值,转移资源所有权 SimpleStructMng(SimpleStructMng&& other) noexcept : SimpleStructBase(std::move(other)), mem(std::move(other.mem)) { other.intPointer = nullptr; } SimpleStructMng& operator=(SimpleStructMng&& other) noexcept { if (this != &other) { SimpleStructBase::operator=(std::move(other)); mem = std::move(other.mem); other.intPointer = nullptr; } return *this; } static SimpleStructMng CreateStruct(SimpleStructBase& params) { SimpleStructMng ret = { params }; ret.mem = std::make_shared<MemHolder>(ret); return ret; } }; int main() { SimpleStructBase objBase; objBase.intPointer = new int(42); SimpleStructMng objMng = SimpleStructMng::CreateStruct(objBase); std::cout << "Base object: " << *objBase.intPointer << "\n"; std::cout << "Managed object: " << *objMng.intPointer << "\n"; delete objBase.intPointer; // 手动释放原对象的独立资源 return 0; }
方案2:调整MemHolder的资源管理逻辑
让MemHolder用智能指针持有内存,确保SimpleStructBase::intPointer始终指向有效内存,即使发生拷贝也能通过shared_ptr的引用计数保证资源不被提前释放:
#include <iostream> #include <string> #include <memory> struct SimpleStructBase { int* intPointer; }; struct MemHolder { std::unique_ptr<int> data; SimpleStructBase& params; MemHolder(SimpleStructBase& dist) : params(dist), data(new int(*dist.intPointer)) { params.intPointer = data.get(); } }; struct SimpleStructMng : SimpleStructBase { protected: SimpleStructMng(SimpleStructBase& params) : SimpleStructBase(params) {} std::shared_ptr<MemHolder> mem; public: ~SimpleStructMng() = default; static SimpleStructMng CreateStruct(SimpleStructBase& params) { SimpleStructMng ret = { params }; ret.mem = std::make_shared<MemHolder>(ret); return ret; } }; int main() { SimpleStructBase objBase; objBase.intPointer = new int(42); SimpleStructMng objMng = SimpleStructMng::CreateStruct(objBase); std::cout << "Base object: " << *objBase.intPointer << "\n"; std::cout << "Managed object: " << *objMng.intPointer << "\n"; delete objBase.intPointer; return 0; }
关键注意点
- 原
SimpleStructBase对象的资源需要手动释放,因为MemHolder仅管理拷贝后的新内存。 - 必须保证
SimpleStructMng的语义正确,避免拷贝/移动操作导致的资源重复释放或野指针问题。
内容的提问来源于stack exchange,提问作者Anton Serov
相关产品推荐
相关产品推荐

