Functions
F.20
Для «выходных» значений предпочитайте возвращаемые значения выходным параметрам
Причина
Возвращаемое значение само себя документирует, тогда как & может быть как «вход-выход», так и только «выход», что чревато злоупотреблениями.
Это относится и к крупным объектам, таким как стандартные контейнеры, использующие неявные операции перемещения для производительности и избегания явного управления памятью.
Если нужно вернуть несколько значений, используйте кортеж или аналогичный тип с несколькими членами.
Пример
// OK: возвращаем указатели на элементы со значением x
vector<const int*> find_all(const vector<int>&, int x);
// Плохо: помещаем указатели на элементы со значением x в out
void find_all(const vector<int>&, vector<const int*>& out, int x);
Примечание
struct из многих (индивидуально дешёвых для перемещения) элементов может быть в совокупности дорогим для перемещения.
Исключения
- Для неконкретных типов, таких как типы в иерархии наследования, возвращайте объект через
unique_ptrилиshared_ptr. - Если тип дорог для перемещения (например,
array<BigTrivial>), рассмотрите выделение в свободном хранилище и возврат дескриптора (например,unique_ptr), или передачу его в ссылку на не-constцелевой объект для заполнения (используется как выходной параметр). - Для повторного использования объекта, несущего ёмкость (например,
std::string,std::vector) в нескольких вызовах функции во внутреннем цикле: трактуйте его как параметр вход/выход и передавайте по ссылке.
Пример
Предполагая, что Matrix имеет операции перемещения (возможно, хранит элементы в std::vector):
Matrix operator+(const Matrix& a, const Matrix& b)
{
Matrix res;
// ... заполнить res суммой ...
return res;
}
Matrix x = m1 + m2; // конструктор перемещения
y = m3 + m3; // оператор присваивания с перемещением
Примечание
Оптимизация возвращаемого значения не обрабатывает случай присваивания, но перемещающее присваивание справляется.
Пример
struct Package { // исключительный случай: дорогостоящий для перемещения объект
char header[16];
char load[2024 - 16];
};
Package fill(); // Плохо: большое возвращаемое значение
void fill(Package&); // OK
int val(); // OK
void val(int&); // Плохо: читает ли val свой аргумент
Контроль
- Помечать ссылки на не-
constпараметры, в которые не производится чтение перед записью и которые являются типом, который мог бы быть дёшево возвращён; они должны быть «выходными» возвращаемыми значениями.