Как конструктор должен сообщать об ошибках? Указатели на внешние флаги? - PullRequest
2 голосов
/ 12 сентября 2011

Я работаю над рефакторингом некоторого старого кода в стиле C, чтобы привести его в соответствие с кодом C ++.Я все еще немного новичок в C ++

Пример кода, над которым я работаю, следующий:

Errmsg foo{
   ErrMsg err = NoError;
   /*
    Some Processing
   */
  err = foo_cleanup(err,/* some parameters*/);
   /*
    Some More Processing
   */
  return err;
}

Я думал о разработке класса, чтобы

class foo_class
{
 public:
   foo_class(Errmsg errmsg_init&,/*Some other arguments */ ):
      errmsg(&errmsg_init),
      /*Initialize other parameters */{}

   void foo_cleanup (/*Other parameters*/);
   // same functionality, but since the source variable is available, 
   // it can be modified without having to return any variable

  ~foo_class(){foo_cleanup(/*Parameters*/);}

   /*
   Member functions
   */

 private:
   Errmsg* errmsg;
   /*Some other parameters */
};

Errmsg foo{
   ErrMsg err = NoError; 
   foo_class foo_obj(err);
   /*
    Some Processing
   */

  // The class would be 
  //cleaned up before returning 
  // and the err variable would be 
  //modified in the destructor
  return err;
}

Хотя мне удалось использовать что-то похожее на этот подход, я не знаю, будет ли это переносимым.

Правильно ли это делать?

Если нет, то могу ли я просто использовать указатели для инициализации класса вместо передачи переменной сообщения об ошибке по ссылке?Или есть что-то еще, что я могу сделать?

Я не могу использовать исключения на текущем этапе, потому что есть много вызовов функций во / из внешнего кода, которые все еще используют подход «возврата сообщения об ошибке».

Ответы [ 3 ]

1 голос
/ 12 сентября 2011

Ваш код опасен, потому что он допускает неправильные варианты использования, такие как:

return new FooClass (local_error_code_variable);

Не пытайтесь сигнализировать об ошибках конструктора с помощью кодов возврата. Вы не можете. Использовать исключения.

Вы можете заключить исключения в коды возврата и наоборот.

class NewAPIClass {
    NewAPIClass () {
        error_code err = old_api_function ();
        if (OLD_API_OK != err)
            throw NewAPIException (err);
    }
}

extern "C" error_code new_api_callback_function (argument arg) {
    try {
        NewAPIClass object;
        object .do_work ();
    }
    catch (...) {
        return OLD_API_ERROR;
    }
}

int main () {
    old_api_install_callback (new_api_callback_function);
}

Исключения важны.Есть много хороших GOTW статей , и вы должны понять их как цель для разработчика на C ++.

Написать новый код, чтобы правильно использовать исключения.Конвертируйте типы ошибок всякий раз, когда вы сталкиваетесь с границей между старым и новым кодом.

Кстати, исключения являются разумным способом * *1019* для конструктора, который может дать сбой.Это все часть RAII, которая является ключом к тому, чтобы сделать C ++ таким мощным.Конструкторы устанавливают ваши инварианты, а исключения сигнализируют о несоблюдении постусловий - соберите все вместе, и вот важная философия: в C ++ должны существовать только допустимые объекты , если вы понимаете это правильноиспользуя RAII, дальнейшее существование объекта является доказательством правильности программы.

1 голос
/ 19 сентября 2011

Оставляя в стороне, что вы должны, если возможно, исправить вызывающий код, чтобы исключение было в порядке, вы можете использовать двухфазную конструкцию:

struct foo_class {
    foo_class() { } // default constructor cannot fail
    Errmsg nothrow_init(/* other params */) throw() {
        /* initialize other parameters */
    }
    foo_class(/* other params */) {
        if (nothrow_init(/* other params */) != ERRMSG_OK) {
            throw something;
        }
    }
};

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

В будущем, когда вы переведете другие части своей кодовой базы в состояние использования исключений, вы обнаружите, что кодв init называет вещи, которые могут сами выбросить.В этот момент вы можете начать перемещать код, так что nothrow_init вызывает функцию init, которая может генерировать, но перехватывает любые исключения и превращает их в коды ошибок.Если предположить, что это внутренний класс, то в конечном итоге ничто не будет использовать nothrow_init, и вы можете удалить его.

0 голосов
/ 12 сентября 2011

Я не могу использовать исключения на текущем этапе, потому что есть много вызовы функций в / из внешнего кода, которые используют «ошибку возврата» сообщение "подходить еще.

Тогда сначала исправьте эту проблему. Тогда используйте исключения.

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