Предупреждение, что вызывающие функции должны обрабатывать - PullRequest
1 голос
/ 06 апреля 2010

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

SomeObject Foo(int input)
{
   SomeObject result;      
   // do something. oh, we need to warn the caller. 

   return result;
}

void Main()
{
   SomeObject object;
   object = Foo(1); // after copy constructor is done I would like an exception to be thrown


}

Ответы [ 3 ]

4 голосов
/ 06 апреля 2010

Вы должны принять более конкретное решение, я думаю.Очень необычно (как-то) предупреждать пользователя функции, давая ему результат.

Например, вы можете вернуть std::pair<SomeObject, std::string>, где предупреждение находится в строке, если таковая имеется.Но людям будет очень легко игнорировать это.

Исключением не является решение: если вы можете продолжать выполнение значимым образом, это не исключительная ситуация.Можно придумать какую-то систему, позволяющую им закончить с исключением «в очереди», но когда это должно быть выброшено?И с какой целью?Конечно, в любом случае это приведет к сокращению оставшейся части работы.

Я думаю, что вы хотите assert.assert что условие выполняется;если этого не произойдет, программист будет уведомлен и может соответствующим образом справиться с ситуацией.Помните, assert предназначены для программистов, исключения - для программы.

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

0 голосов
/ 06 апреля 2010

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

Когда компилятор просматривает каждый кадр стека, он очищает все локальные переменные в этом кадре - поэтому, даже если ваша функция должна была вернуть значение, а затем было сгенерировано исключение «после того, как функция уже завершилась», возвращаем Значение будет очищено в любом случае, так как компилятор разматывает стек. Так какой смысл ждать завершения функции? Просто тут же бросьте исключение:

SomeObject foo(int input)
{
   SomeObject result;

   // Do stuff

   // Something goes wrong in an unrecoverable fashion
   throw BadThingHappenedException;

   // More code for the good case
   return result;
}
0 голосов
/ 06 апреля 2010

Бросок «исключения» и продолжение «возврата нормального значения» противоречат.

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

Чтобы запретить вызывающей стороне не обрабатывать ошибку, вы можете создать «сигнальный элемент» таким образом, чтобы, если вызывающая сторона не опрашивала его, вы утверждали в деструкторе SomeObject (или в деструкторе сигнального элемента).

Возможный пример сигнального элемента:

template <typename Base>
class Signal
{
private:
  Base _val;
  bool _polled;

public:
  operator Base() const {_polled=true;return _val;}
  // even when we do not set the value, we force the user to poll - it makes testing easier
  Signal():_polled(false) {}
  // but once we set it, we mark he has to poll
  Signal(Base val):_val(val),_polled(false) {}
  // if he does not, we assert
  ~Signal(){assert(_polled);}
};

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

SomeObject Foo(int input, Signal<int> &errorCode)
{
  SomeObject result;      
  // do something. 
  if (somethingBadHappened)
    errorCode = 1234; //oh, we need to warn the caller. 

  return result;
}

void Main()
{
  SomeObject object;
  Signal<int> error;
  object = Foo(1,error);

  // error not served? => assert
  // to prevent the assert firing, uncomment the following line
  // int handle = error;
}

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

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