Если конструктор выдает исключение, имеет ли смысл иметь глобальный объект этого класса? - PullRequest
8 голосов
/ 08 августа 2011

Я задаю этот вопрос для общих правил кодирования:

class A {
  A() { ... throw 0; }
};
A obj;  // <---global

int main()
{
}

Если obj выдает исключение в вышеприведенном коде, то в конечном итоге код завершится до вызова main(). Итак, мой вопрос, какое руководство я должен принять для такого сценария? Можно ли объявлять глобальные объекты для таких классов или нет? Должен ли я всегда воздерживаться от этого, или это хорошая тенденция ловить ошибку в самом начале?

Ответы [ 6 ]

4 голосов
/ 08 августа 2011

Если вы NEED глобальный экземпляр объекта, конструктор которого может генерировать, вы могли бы сделать переменную статической, вместо этого:

A * f(){

   try {

      //lock(mutex);   -> as Praetorian points out
      static A a;
      //unlock(mutex);

      return &a;
   }
   catch (...){

      return NULL;
   }
}

int main() {

   A * a = f(); //f() can be called whenever you need to access the global

}

Это уменьшит проблему, вызванную преждевременнымисключение.

РЕДАКТИРОВАТЬ: Конечно, в этом случае решение на 90% пути к синглтону.Почему бы просто полностью не превратить его в единое целое, переместив f() в A?

1 голос
/ 08 августа 2011

Нет, вы не должны объявлять такие объекты глобальными - любое исключение будет необработанным и очень трудно диагностируемым. Программа просто рухнет, что означает, что она будет иметь очень плохой (ниже нуля) пользовательский опыт и будет довольно трудно поддерживать.

0 голосов
/ 19 ноября 2017

Как сказал @JT, вы можете написать так:

struct S {
  S() noexcept(false);
};

S &globalS() {
  try {
    static S s;
    return s;
  } catch (...) {
    // Handle error, perhaps by logging it and gracefully terminating the application.
  }
  // Unreachable.
}

Такой сценарий довольно проблематичен, пожалуйста, прочитайте ERR58-CPP.Обработайте все исключения, сгенерированные до того, как main () начнет выполнять для более подробной информации.

0 голосов
/ 08 августа 2011

Одно из решений, о которых никто не упомянул, - это использовать функцию try блок. В принципе, если ситуация такова, что без объект, остальная часть вашей программы не будет работать или делать что-либо полезно, тогда единственная реальная проблема в том, что ваш пользователь получит какую-то непонятного сообщения об ошибке, если конструктор завершается исключение. Таким образом, вы заключаете конструктор в блок try функции, и сгенерировать понятное сообщение с возвращением ошибки:

A::() try
    : var1( initVar1 )
    // ...
{
    //  Additional initialization code...
} catch ( std::exception const& ) {
    std::cerr << "..." << std::endl;
    exit(EXIT_FAILURE);
} catch (...) {
    std::cerr << "Unknown error initializing A" << std::endl;
    exit(EXIT_FAILURE);
}

Это решение действительно уместно только в том случае, если все объект объявляется статически, или если вы можете выделить один конструктор для статических экземпляров; для нестатических случаев это Вероятно, лучше распространять исключение.

0 голосов
/ 08 августа 2011

Объявление глобального объекта - это хорошо, но дизайн вашего класса незначителен, в нем отсутствуют детали, чтобы быть совместимым с практическими потребностями и использованием.

0 голосов
/ 08 августа 2011

Как упомянул @Kerrek SB в комментариях, ответ на этот вопрос зависит от причин, которые могут вызвать ваш класс. Если вы пытаетесь получить системный ресурс, который может быть недоступен, я чувствую, что вы не должны объявлять глобальный объект. Ваша программа потерпит крах, как только пользователь попытается ее запустить; Излишне говорить, что это выглядит не очень хорошо. Если он может выдать std::bad_alloc или какое-либо подобное исключение, которое маловероятно при нормальных обстоятельствах (если вы не пытаетесь выделить несколько ГБ памяти), вы можете создать глобальный экземпляр; однако я бы все равно не сделал этого.

Вместо этого вы можете объявить глобальный указатель на объект, создать экземпляр объекта прямо в начале main (до того, как будут созданы все потоки и т. Д.) И указать указатель на этот экземпляр, а затем получить к нему доступ через указатель. , Это дает вашей программе возможность обрабатывать исключения и, возможно, побуждать пользователя предпринять какие-то коррективные меры (например, нажать кнопку «Повторить», чтобы попытаться повторно получить ресурс).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...