2016-10-30 5 views
1

Я пишу класс Matrice (ради практики), и когда я написал метод умножения двух объектов Matrice я должен был проверить, если определенные условия для умножения матриц:Что вернуть из метода, если определенные условия не были выполнены?

Matrix Matrix::mul(const Matrix &mat) 
{ 
    if(col != mat.row) 
     //we cannot multiply in this case 
    else 
    { 
     //create temp object result 
     //perform multiplication 
     return result; 
    } 
} 

Теперь я любопытный что делать, если условие не выполнено, потому что еще в main.cpp я бы написать что-то вроде этого:

Matrix a = b.mul(c); 

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

+0

возвращение 'std :: optional' или бросок. – Incomputable

+0

Если ваши матрицы имеют фиксированный размер (и константы времени компиляции), вы можете перемещать размеры в параметры шаблона. Затем (если у вас есть подпись), компилятор не позволит вам умножать матрицы неправильных размеров :) – StoryTeller

+0

Они динамически созданы, но спасибо – adadaae12313412

ответ

2

Ничего не вернуть, бросить exception вместо:

if (failure) 
    throw std::runtime_error("Exception!!"); 

Вы можете бросить любого из different exceptions, который подходит вашему делу больше.

Кстати, вы можете посмотреть мой проект под названием Матрицаon GitHub для примера того, как можно создать такой класс для работы с матрицами.

2

Чтобы справиться с предпосылками вы можете

  • сгенерирует исключение.
  • Возврат C++ 17 std::optional, или boost::optional.
  • Звоните std::terminate.

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

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

1

Каковы возможные подходы?

  1. возврата некоторое нейтральное значение, которое показывает существует проблема (например, пустая матрица)
  2. обработать ошибку, но только при отладке: например, используйте assert() для проверки и предварительных условий документа, а также для инвариантов.
  3. выдать исключение, чтобы сообщить, что есть проблема: позвольте вызывающему абоненту (или вызывающему абоненту) решить, что делать. Если исключение не улавливается, код прерывается. Приятно, что вы можете предоставить дополнительную информацию об ошибке.

Какой из них выбрать?

Решение (1) должно использоваться, если часто возникает ошибка (почти нормальная), и функция вызывается часто. Я бы не советовал вам использовать его здесь.

Решение (2) может быть использовано, если условие ошибки не ожидается, и вы уверены, что ситуация с ошибкой предотвращена (например, пользовательский интерфейс предотвратит такие ошибки).

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

Пример для решения 3:

Вместо использования общего назначения exception или создать свой собственный специфический характер, можно использовать domain_error (домен в математическом смысле, т.е. аргумент является допустимым значением, но функция не определена для этого значения) или invalid_argument:

// in your multiplication 
... 
if(col != mat.row) 
    throw std::invalid_argument ("Matrix multiplication operand of incompatible size"); 
... 

// In the calling program: 
... 
try { 
    a = b.mul(c); 
} 
catch (std::invalid_argument &e) { 
    cout << "Invalid argument provided: " << e.what()<<endl; 
} 
0

что я должен вернуться?

Это зависит от ваших требований.

Это лучший способ бросить исключение

Это может быть. Это зависит от ваших требований.


У вас есть несколько вариантов:

  1. Прервать процесс. Разработчик может проанализировать дамп ядра, чтобы выяснить, что произошло. Преимущество этого в том, что ошибка трудно пропустить.

  2. Даже не проверяйте предварительные условия внутри функции. Просто укажите предварительные условия. Если вызывающий абонент нарушает предусловия, поведение не определено. Это наиболее эффективное решение, но полагается на правильность использования функции.

  3. Проверьте состояние с помощью assert. Если тест завершился неудачно, процесс завершается. Утверждения отключены с помощью макроса NDEBUG, поэтому вы можете отключить проверку для оптимальной производительности. Это позволяет выбирать 1. или 2. в зависимости от сборки debug vs release, поэтому она более гибкая, чем любая.

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

  5. std::optional. Это позволяет вызывающему лицу проверить, есть ли возвращаемое значение, и решить, какой из вариантов 1 ... 4 они хотят использовать для обработки отсутствующего. Если вызывающий абонент игнорирует возможность несуществующего возвращаемого значения, то по умолчанию он равен 2. (неопределенное поведение).

Смежные вопросы