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

C++代码遇Segmentation Fault:初始化列表可行,拷贝构造函数失效

解决C++构造函数中Button赋值导致的Segmentation Fault问题

你的段错误核心原因是Button类的浅拷贝问题:默认拷贝构造函数只会逐成员复制,如果Button内部持有裸指针(比如指向动态内存、SDL纹理/窗口句柄这类系统资源),临时Button对象销毁时会释放这些资源,而你赋值给Game的成员变量后,成员变量里的指针就指向了已释放的内存,后续访问必然触发段错误。

以下是几种可行的解决方案:

1. 给Button实现深拷贝的拷贝构造函数和赋值运算符

手动编写拷贝逻辑,复制资源而非仅复制指针,确保每个Button实例拥有独立的资源副本。同时实现赋值运算符(遵循拷贝交换惯用法),避免内存泄漏和重复释放。

示例代码:

#include <SDL2/SDL.h>
#include <algorithm> // 用于std::swap

class Button {
private:
    SDL_Texture* m_texture;
    SDL_Rect m_rect;
    std::string m_text;
    SDL_Renderer* m_renderer; // 假设需要持有渲染器指针

public:
    // 普通构造函数
    Button(SDL_Renderer* renderer, const std::string& text, int x, int y)
        : m_renderer(renderer), m_text(text), m_rect{x, y, 100, 50} {
        // 创建纹理的逻辑
        SDL_Surface* surface = TTF_RenderText_Solid(/* 字体指针 */, text.c_str(), {255,255,255,255});
        m_texture = SDL_CreateTextureFromSurface(renderer, surface);
        SDL_FreeSurface(surface);
    }

    // 拷贝构造函数:深拷贝资源
    Button(const Button& other)
        : m_renderer(other.m_renderer), m_text(other.m_text), m_rect(other.m_rect) {
        // 从原纹理复制出新的纹理
        SDL_Surface* surface = SDL_GetSurfaceFromTexture(other.m_texture);
        m_texture = SDL_CreateTextureFromSurface(m_renderer, surface);
        SDL_FreeSurface(surface);
    }

    // 赋值运算符:拷贝交换惯用法
    Button& operator=(Button other) {
        std::swap(m_texture, other.m_texture);
        std::swap(m_rect, other.m_rect);
        std::swap(m_text, other.m_text);
        return *this;
    }

    // 析构函数:释放资源
    ~Button() {
        if (m_texture) {
            SDL_DestroyTexture(m_texture);
        }
    }
};

2. 使用智能指针管理Button内部资源

将Button中的裸指针替换为std::unique_ptr或std::shared_ptr,配合自定义删除器处理系统资源的释放。默认的拷贝构造/赋值会自动处理资源的转移或共享,无需手动编写深拷贝逻辑。

示例代码:

#include <SDL2/SDL.h>
#include <memory>

// 自定义SDL纹理删除器:确保资源正确释放
struct SDLTextureDeleter {
    void operator()(SDL_Texture* tex) const {
        if (tex) {
            SDL_DestroyTexture(tex);
        }
    }
};

class Button {
private:
    // 使用unique_ptr管理纹理,独占资源所有权
    std::unique_ptr<SDL_Texture, SDLTextureDeleter> m_texture;
    SDL_Rect m_rect;
    std::string m_text;

public:
    Button(SDL_Renderer* renderer, const std::string& text, int x, int y)
        : m_text(text), m_rect{x, y, 100, 50} {
        SDL_Surface* surface = TTF_RenderText_Solid(/* 字体指针 */, text.c_str(), {255,255,255,255});
        m_texture.reset(SDL_CreateTextureFromSurface(renderer, surface));
        SDL_FreeSurface(surface);
    }

    // 如果需要拷贝Button实例,改用shared_ptr共享资源
    // std::shared_ptr<SDL_Texture, SDLTextureDeleter> m_texture;
};
  • 用unique_ptr时,赋值需要通过std::move转移资源所有权,避免浅拷贝;
  • 用shared_ptr时可直接拷贝,资源会通过引用计数管理,最后一个持有者销毁时才释放资源。

3. 直接原位构造Game的Button成员

如果不想修改Button类,可以给Button添加带参数的构造函数,直接在Game的构造函数初始化列表中创建Button成员,跳过默认构造后赋值的步骤,从根本上避免临时对象的创建。

示例代码:

class Game {
private:
    Button m_startButton;
    Button m_exitButton;

public:
    // 直接在初始化列表中构造Button,无需临时对象
    Game(SDL_Renderer* renderer)
        : m_startButton(renderer, "Start", 100, 200),
          m_exitButton(renderer, "Exit", 300, 200) {}
};

内容的提问来源于stack exchange,提问作者DR4NKR1D3R

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 16:04:52