Примечание: этот ответ относится только к C ++ 11 и далее. Нет такого понятия, как "C / C ++", это разные языки.
Нет, возвращать локальный объект по значению не опасно, и это рекомендуется делать. Однако я думаю, что во всех ответах здесь отсутствует важный момент. Многие другие сказали, что структура либо копируется, либо размещается напрямую с помощью RVO. Однако это не совсем так. Я постараюсь объяснить, что именно может произойти при возврате локального объекта.
Семантика перемещения
Начиная с C ++ 11, у нас были ссылки на rvalue, которые являются ссылками на временные объекты, которые можно безопасно украсть. Например, std :: vector имеет конструктор перемещения, а также оператор присваивания перемещения. Оба они имеют постоянную сложность и просто копируют указатель на данные перемещаемого вектора. Я не буду здесь вдаваться в подробности семантики перемещения.
Поскольку объект, созданный локально внутри функции, является временным и выходит за пределы области видимости при возврате из функции, возвращенный объект никогда не копируется в C ++ 11 и далее. Конструктор перемещения вызывается для возвращаемого объекта (или нет, как будет объяснено позже). Это означает, что если вы должны вернуть объект с помощью дорогостоящего конструктора копирования, но недорогого конструктора перемещения, например большого вектора, от локального объекта к возвращаемому объекту передается только право собственности на данные, что обходится дешево.
Обратите внимание, что в вашем конкретном примере нет разницы между копированием и перемещением объекта. Конструкторы перемещения и копирования по умолчанию для вашей структуры приводят к одним и тем же операциям; копирование двух целых чисел. Однако это по крайней мере так же быстро, как любое другое решение, потому что вся структура помещается в 64-битный регистр ЦП (поправьте меня, если я ошибаюсь, я не знаю много регистров ЦП).
RVO и NRVO
RVO означает оптимизацию возвращаемого значения и является одной из немногих оптимизаций, которые делают компиляторы и которые могут иметь побочные эффекты. Начиная с c ++ 17 требуется RVO. При возврате безымянного объекта он создается непосредственно на месте, где вызывающий объект присваивает возвращаемое значение. Ни конструктор копирования, ни конструктор перемещения не вызываются. Без RVO безымянный объект сначала был бы построен локально, затем был бы создан перемещением по возвращенному адресу, а затем локальный безымянный объект был бы разрушен.
Пример, когда требуется RVO (c ++ 17) или вероятно (до c ++ 17):
auto function(int a, int b) -> MyStruct {
return MyStruct{a, b};
}
NRVO означает оптимизацию именованного возвращаемого значения и то же самое, что и RVO, за исключением того, что это делается для именованного объекта, локального для вызываемой функции. Это все еще не гарантируется стандартом (c ++ 20), но многие компиляторы все еще это делают. Обратите внимание, что даже с именованными локальными объектами они в худшем случае перемещаются при возврате.
Заключение
Единственный случай, когда вам следует рассмотреть возможность отказа от возврата по значению, - это когда у вас есть именованный, очень большой (как по размеру стека) объект. Это связано с тем, что NRVO еще не гарантирован (начиная с C ++ 20), и даже перемещение объекта будет медленным. Моя рекомендация и рекомендация в Cpp Core Guidelines - всегда отдавать предпочтение возврату объектов по значению (если возвращаются несколько значений, используйте структуру (или кортеж)), где единственное исключение - когда перемещение объекта дорого. В этом случае используйте неконстантный ссылочный параметр.
НИКОГДА не рекомендуется возвращать ресурс, который нужно вручную освободить из функции в C ++. Никогда не делай этого. По крайней мере, используйте std :: unique_ptr или создайте свою собственную нелокальную или локальную структуру с деструктором, который освобождает свой ресурс ( RAII ) и возвращает экземпляр этого. Тогда также было бы неплохо определить конструктор перемещения и оператор присваивания перемещения, если ресурс не имеет собственной семантики перемещения (и удалить конструктор / присваивание копии).