构造函数中的异常

Exception in constructor

本文关键字:异常 构造函数      更新时间:2023-10-16

我看过一些关于这个主题的话题,但是我真的不明白…

有足够的耐心告诉我如何才能使这个构造函数正确?

SdlManager::SdlManager() {
    //SDL init
    if(SDL_Init(SDL_INIT_VIDEO) < 0) {
      std::cerr << "Could not initialize SDL: " << SDL_GetError() << std::endl;
      goto error1;
    }
    //Init mutex for SDL access
    m_mutex = SDL_CreateMutex();
    if (m_mutex == nullptr)
      goto error2;
    try {
      m_display = DisplayManager(m_mutex, false);
      m_events = EventManager(m_mutex);
    }
    catch (void* _) {
      goto error3;
    }
    return;
    //Error Handling
  error3:
    SDL_DestroyMutex(m_mutex);
  error2:
    SDL_Quit();
  error1:
    throw ;
  }

欢迎提出建议。

谢谢祝你过得愉快。

编辑:

关于错误:

src/sdl_manager.cpp:6:1: error: uninitialized reference member in ‘class sdl::DisplayManager&’ [-fpermissive]
     SdlManager::SdlManager() {
     ^
    In file included from src/sdl_manager.cpp:2:0:
    ./src/include/sdl_manager.hpp:13:20: note: ‘sdl::DisplayManager& sdl::SdlManager::m_display’ should be initialized
        DisplayManager& m_display;
                        ^
    src/sdl_manager.cpp:6:1: error: uninitialized reference member in ‘class sdl::EventManager&’ [-fpermissive]
     SdlManager::SdlManager() {
     ^
    In file included from src/sdl_manager.cpp:2:0:
    ./src/include/sdl_manager.hpp:14:19: note: ‘sdl::EventManager& sdl::SdlManager::m_events’ should be initialized
        EventManager&  m_events;
                       ^

似乎我的try-catch块不是很好

EDIT2:

我只是把sdl_manager.hpp。

#ifndef  SDL_MANAGER_HPP
#define  SDL_MANAGER_HPP
#include  <SDL2/SDL_mutex.h>
#include  "display_manager.hpp"
#include  "event_manager.hpp"
namespace  sdl
{
  class  SdlManager {
    private:
      SDL_mutex*      m_mutex;
      DisplayManager& m_display;
      EventManager&   m_events;
    public:
      SdlManager();
      ~SdlManager();
  };
}
#endif

所以,这不是现代习惯的c++的样子,这就是为什么它令人困惑的原因。

  1. 不要使用"goto",这里绝对没有理由。
  2. 使用RAII习语来简化这些东西。

基本上在上面的代码中,你使用"goto"而不是使用析构函数。这是基于RAII习惯用法的代码的样子。

struct Sdl_error : public std::exception {
  ...
};
struct Sdl_Init_RAII {
  Sdl_Init_RAII()
  {
    if(SDL_Init(SDL_INIT_VIDEO) < 0) {
      std::cout << "Could not initialize SDL: " << SDL_GetError() << std::endl;
      throw Sdl_error();
    }
  }
  ~Sdl_Init_RAII()
  {
    SDL_Quit();
  }
};
struct Sdl_Mutex {
  SDL_Mutex * m_ptr;
  Sdl_Mutex()
    : m_ptr(SDL_CreateMutex())
  {
    if (m_ptr == nullptr) throw Sdl_error();
  }
  ~Sdl_Mutex()
  {
    if (m_ptr) { SDL_DestroyMutex(m_ptr); }
  }
};
SdlManager::SdlManager
  : m_init()
  , m_mutex()
  , m_displayer(m_mutex.m_ptr, false)
  , m_events(m_mutex.m_ptr)
{}

请注意,您稍微更改了代码示例,但是您应该在SdlManager中添加一个名为m_initSdl_Init_RAII类型的成员,以便上述代码片段有意义。

注意SdlManager不需要在这里有析构函数,因为它本身不直接管理任何C资源。但是,显示,事件,互斥都是这样。而且Sdl_Init_RAII也存在,即使它没有成员变量——它的目的是强制执行合约,无论何时我们调用C函数SDL_Init,我们稍后也会调用SDL_Quit。当你有一个C库强加了一些这样的要求时,使用RAII对象来确保你的c++程序符合要求通常是一个好主意。

编辑:既然你特别发布了错误信息,我可以看到我的重构也会修复它。问题是,当你有一个成员变量是引用的构造函数时,你必须在初始化列表中初始化它,否则它不能绑定到函数开头的任何东西(!),语言根本不允许这样做,禁止这是引用的整个点。

错误uninitialized reference member表示您声明了m_displaym_events作为引用。这些必须在构造函数的初始化列表中初始化,如下所示:

SdlManager::SdlManager(DisplayManager& display, EventManager& events)
: m_mutex(nullptr)
, m_display(display)
, m_events(events)
{
    ...
}