В C++11 все еще существует необходимость передавать ссылку на объект, который будет принимать выходные данные функции?
До C++11, если бы у меня была функция, которая работала с большими объектами, мой инстинкт был бы писать функции с таким прототипом.
void f(A &return_value, A const ¶meter_value);
(Здесь return_value - это просто пустой объект, который будет получать выходные данные функции. A - это просто некоторый класс, который является большим и дорогим для копирования.)
В C++11, используя преимущества семантики перемещения, рекомендация по умолчанию (насколько я понимаю) является более простой:
A f(A const ¶meter_value);
Есть ли еще необходимость делать это по-старому, передавая объект для хранения возвращаемого значения?
3 ответа
Другие охватили случай, когда A
может не иметь дешевого конструктора перемещения. Я предполагаю, что ваш A
делает. Но есть еще одна ситуация, когда вы можете передать параметр out:
Если A
это какой-то тип, как vector
или же string
и известно, что параметр "out" уже имеет ресурсы (например, память), которые могут быть повторно использованы внутри f
, тогда имеет смысл повторно использовать этот ресурс, если вы можете. Например, рассмотрим:
void get_info(std::string&);
bool process_info(const std::string&);
void
foo()
{
std::string info;
for (bool not_done = true; not_done;)
{
info.clear();
get_info(info);
not_done = process_info(info);
}
}
против:
std::string get_info();
bool process_info(const std::string&);
void
foo()
{
for (bool not_done = true; not_done;)
{
std::string info = get_info();
not_done = process_info(info);
}
}
В первом случае потенциал будет расти в string
по мере выполнения цикла, и эта емкость затем потенциально используется повторно на каждой итерации цикла. Во втором случае новый string
распределяется на каждой итерации (без учета буфера оптимизации небольших строк).
Теперь это не значит, что вы никогда не должны возвращаться std::string
по значению. Просто вы должны знать об этой проблеме и применять инженерное решение в каждом конкретном случае.
Это зависит от того, поддерживает ли ваш компилятор оптимизацию возвращаемого значения, и является ли ваша функция f
разработан, чтобы иметь возможность использовать RVO, поддерживаемый вашим компилятором?
Если это так, то да, во что бы то ни стало вернуть по значению. Вы ничего не получите, передав изменяемый параметр, и вы получите большую ясность кода, если будете делать это таким образом. Если нет, то вы должны изучить определение A
,
Для некоторых типов перемещение - это не что иное, как копия. Если A
не содержит ничего, что действительно стоит переместить (указатели, передающие право собственности и т. д.), то вы ничего не получите, переместившись. Движение не является свободным, в конце концов; это просто копия, которая знает, что все, что принадлежит оригиналу, передается копии. Если типу ничего не принадлежит, перемещение - это просто копия.
Возможно, что объект будет большим и дорогим для копирования, и для которого семантика перемещения не может улучшить копирование. Рассматривать:
struct A {
std::array<double,100000> m_data;
};
Возможно, не очень хорошая идея проектировать ваши объекты таким образом, но если у вас есть объект этого типа по какой-то причине и вы хотите написать функцию для заполнения данных, то вы можете сделать это с помощью параметра out.