Все сводится к контракту , который обеспечивает интерфейс. Для этого есть два разных сценария: входы и выходы.
Входные данные - и под этим я в основном имею в виду параметры функций - должны проверяться реализацией как общее правило.
Выводы, являющиеся возвращаемыми результатами, должны в основном вызываться вызывающим абонентом, по крайней мере, на мой взгляд.
Все это смягчается вопросом: что произойдет, если одна из сторон нарушит договор? Например, допустим, у вас был интерфейс:
class A {
public:
const char *get_stuff();
}
и в этом контракте указывается, что пустая строка никогда не будет возвращена (в худшем случае это будет пустая строка), тогда это можно сделать безопасно:
A a = ...
char buf[1000];
strcpy(buf, a.get_stuff());
Почему? Ну, если вы не правы, и вызываемый возвращает ноль, то программа завершится сбоем. Это на самом деле ОК . Если какой-либо объект нарушает его контракт, то, вообще говоря, результат должен быть катастрофическим.
Риск чрезмерной защиты заключается в том, что вы пишете много ненужного кода (который может привести к большему количеству ошибок) или что вы действительно можете замаскировать серьезную проблему, проглотив исключение, которое вам на самом деле не следует.
Конечно, обстоятельства могут изменить это.