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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 03:07:04