Обработка ошибок в конструкторе без сбоев - PullRequest
0 голосов
/ 09 октября 2019

В настоящее время я создаю библиотеку, которая анализирует определения XML для конфигураций оборудования (полученные от производителя). Я сопоставил типы XML с классами c ++, и я использую std::optional там, где есть необязательный член XML, когда семантически правильно пропустить этот фрагмент данных.

Iсейчас пытаюсь придумать хорошую стратегию обработки ошибок для моих типов данных. Иногда в XML может отсутствовать некоторая информация, помеченная схемой как required, или не может быть найден обязательный элемент (что будет отличаться от ошибки в элементе, в котором отсутствуют обязательные данные).

Основная идея для всех типов следует этому (примеру) классу:

class TMyXmlType {
  std::string name;
  std::optional<int> factor;
  std::optional<int> minFactor;
  std::optional<int> maxFator;
public:
  TMyXmlType(const xml_node & root){
    if(root){ // Check if the element exists
    name = root.value();
      if(root.has_child("factor"){ factor = root.child("factor").value(); }
      if(root.has_child("minFactor"){ factor = root.child("minFactor").value(); }
      if(root.has_child("maxFator"){ factor = root.child("maxFator").value(); }
    }else{
      // What do I do here?
    }
  } 
  operator Json::Value() const {
    if(/*object constructed correctly?*/){
      Json::Value asJson;
      asJson["name"] = name;
      if(factor.has_value()){ asJson["factor"] = factor.value(); }
      if(minFactor.has_value()){ asJson["minFactor"] = minFactor.value(); }
      if(maxFator.has_value()){ asJson["maxFator"] = factor.maxFator(); }
      return asJson;
    }else{
      // return error object?
    }
  }
}

Пока все хорошо. О дополнительных членах заботятся. Однако root может быть пустым узлом (библиотека синтаксического анализа xml возвращает пустой узел, если он не был найден). В основном я хочу вернуть объект ошибки вместо значения класса (в моей операторной функции), если один или несколько требуемых узлов XML не были найдены.

Насколько я смог найти, для современныхВ C ++ вы должны выбросить исключение, если конструктор не может правильно сконструировать объект, однако, если я сгенерирую исключение, мои агрегированные типы данных будут иметь массивные конструкторы с кучей блоков try / catch для каждого необходимого элемента данных,что сделало бы кодовую базу трудной для чтения и поддержки.

Итак, теперь возникает вопрос: каков был бы самый чистый способ заставить оператор возвращать объект ошибки вместо данных класса, если требуемый членотсутствует?

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

1 Ответ

0 голосов
/ 09 октября 2019

Просто и ясно, когда вы не хотите ошибиться, не делайте ничего фантастического - например. просто сделайте:

class TMyXmlType {
  std::string name;
  std::optional<int> factor;
  std::optional<int> minFactor;
  std::optional<int> maxFator;
public:
  TMyXmlType(const xml_node & root){
    if(root){ // Check if the element exists
    name = root.value();
      if(root.has_child("factor"){ factor = root.child("factor").value(); }
      if(root.has_child("minFactor"){ factor = root.child("minFactor").value(); }
      if(root.has_child("maxFator"){ factor = root.child("maxFator").value(); }
    }else{
      name = "NODE_ERROR";
    }
  } 
}

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

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


Проверка, найден ли узел для поиска, должнабыть сделано на уровне, вызывающем поиск. Например. следующий код кажется мне разумным:

const auto& node_found = searchNode(...);

const auto optXmlType = node_found ? std::make_optional<TMyXmlType>(node_found) : std::nullopt;

Однако вы можете захотеть обернуть это в функцию.

...