Копирует значения возвращаемой инструкции
Мне интересно об этом из-за проблем с областью. Например, рассмотрим код
typedef struct {
int x1;/*top*/
int x2;/*bottom*/
int id;
} subline_t;
subline_t subline(int x1, int x2, int id) {
subline_t t = { x1, x2, id };
return t;
}
int main(){
subline_t line = subline(0,0,0); //is line garbage or isn't it? the reference
//to subline_t t goes out of scope, so the only way this wouldn't be garbage
//is if return copies
}
Итак, мой вопрос: всегда ли будет возвращать оператор return? В этом случае это работает, поэтому я убежден, что возвращение копирует. Если он копирует, будет ли он копироваться в каждом случае?
Ответы
Ответ 1
Да, в этом случае будет сделана копия. Если вы измените объявление функции следующим образом:
subline_t &subline(int x1, int x2, int id) {
то копия не будет сделана. Однако в вашем конкретном случае было бы неверным возвращать ссылку на объект, выделенный в стеке. Проблема в том, что объект будет уничтожен и аннулирован до того, как у вызывающего есть возможность его использовать.
Это связано с общей Оптимизацией возвращаемого значения для С++, которая может избежать выполнения реальной операции копирования в случае, описанном вами. Конечный результат (или должен быть) такой же, как если бы была сделана копия, но вы должны знать об оптимизации. Наличие этой оптимизации может в некоторых случаях изменять наблюдаемое поведение программы.
Ответ 2
Он всегда будет возвращать копию.
Если вы хотите избежать удара производительности при копировании возвращаемого объекта, вы можете объявить указатель, построить экземпляр объекта с помощью нового и вернуть указатель. В этом случае указатель будет скопирован, но объект не будет.
Ответ 3
В вашем случае он вернет копию
Если ваш код был
subline_t& subline(int, int)
то он вернет ссылку, которая будет работать в режиме undefined.
Ответ 4
Да, для функции, объявленной для возврата struct
, return
такой структуры будет ее скопировать (хотя компилятор имеет право оптимизировать копию, по существу, в тех случаях, когда она может доказать, что оптимизация является семантически безобидной, вы можете рассуждать "как будто" было гарантировано копирование).
Однако, поскольку вы отметили это как С++, а не C, почему бы не поставить вместо struct
конструктор...? Кажется яснее и более прямым...! -)
Ответ 5
да, возврат - это копия
subline_t subline(int x1, int x2, int id) {
subline_t t = { x1, x2, id };
return t;
}
Если вы поместите референс, то это не копия
subline_t & subline(int x1, int x2, int id) {
subline_t t = { x1, x2, id };
return t; // will result in corruption because returning a reference
}
Ответ 6
Он возвращает копию, которую вы хотите сделать. Изменение его для возврата ссылки приведет к поведению undefined в присваивании линии.
Однако, идиоматический способ сделать это в С++ - это конструкторы и списки назначений. Это улучшает структуру кода и данных и позволяет избежать множества промежуточных объектов, которые компиляторы могут свободно создавать/уничтожать/копировать.
struct subline_t {
int x1;/*top*/
int x2;/*bottom*/
int id;
// constructor which initialises values with assignment list.
subline_t(int the_x1, int the_x2, int the_id) :
x1(the_x1),
x2(the_x2),
id(the_id)
{
}
};
int main(){
subline_t line2(0,0,0); // never requires a copy or assignment.
}
Ответ 7
Для структуры subline_t
, которую вы определили, да, она всегда будет возвращать копию.
Ответ 8
Сохранение объектов в С++ выполняется по значению, а не по ссылке.
ссылка на subline_t t выходит за рамки
Нет, объект копируется.
будет всегда возвращать оператор return
Да и не... Семантически это ведет себя как копия, но есть что-то, что называется оптимизацией возвращаемого значения, которое сохраняет конструктор копирования.
foo make_foo()
{
foo f(1,2,3);
return f;
}
foo ff=make_foo(); /// ff created as if it was created with ff(1,2,3) -- RVO
foo ff2;
ff2=make_foo(); /// instance of foo created and then copied to ff2 and then old
/// instance destroyed
Ответ 9
Возвращаемый класс или структура могут копироваться или не копироваться, в зависимости от того, использует ли компилятор копию. См. Ответы на Что такое оптимизация кода и возврат значения? Короче говоря, скопировано или нет, зависит от ряда факторов.
Конечно, вы можете избежать копирования, вернув ссылку. В случае вашего примера возврат ссылки недействителен (хотя компилятор разрешит это), поскольку локальная структура выделяется в стеке, и поэтому возвращаемая ссылка относится к удаленному объекту. Однако, если объект был передан вашей функции (напрямую или как член объекта), вы можете спокойно вернуть ссылку на нее и избежать копирования при возврате.
Наконец, если вы не можете доверять копированию и хотите избежать копий, вы можете использовать и возвращать unique_ptr
вместо ссылки. Сам объект не будет скопирован, хотя сам unique_ptr
может быть или не быть (опять же, в зависимости от копирования!). Копирование/перемещение a unique_ptr
, однако, очень дешево, если копия elision unique_ptr
по какой-то причине не происходит.
Вот пример использования unique_ptr
:
#include <memory>
struct A {
public:
int x;
int y;
A(int x, int y) : x(x), y(y) {
}
};
std::unique_ptr<A> returnsA() {
return std::make_unique<A>(3, 4);
}
int main() {
auto a = returnsA();
}
Обратите внимание, что вы должны (к сожалению) объявить конструктор для своей структуры, иначе make_unique
не будет компилироваться из-за неадекватности С++.
Ответ 10
Просто FYI, так как в этом случае вы используете только struct (ure), это то же поведение, что и на языке C.
Хотя это языковая функция, рекомендуется не использовать ее