构造函数中的异常

时间:2015-08-21 14:00:32

标签: c++ constructor c++14 sdl-2

我看到了一些关于这个主题的话题,但我真的不明白......

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

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

2 个答案:

答案 0 :(得分:2)

所以,这不是现代惯用的C ++的样子,这就是它令人困惑的原因。

  1. 不要使用“转到”这里绝对没有理由。
  2. 使用RAII习惯用法来简化这些内容。
  3. 基本上在上面的代码中,您使用的是“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)
    {}
    

    请注意,您更改了一点点发布的代码示例,但是您应该将Sdl_Init_RAII m_init类型的成员添加到SdlManager,以便上面的代码剪切有意义。< / p>

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

    编辑:现在您已经专门发布了错误消息,我可以看到我的重构也将修复它。问题是,当你有一个带有成员变量的构造函数作为引用时,你必须在initalizer列表中初始化它,否则它不能绑定到函数开头的任何东西(!),语言只是不允许这样做,禁止这就是整个参考点。

答案 1 :(得分:1)

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

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