Возвращает ли оператор copy значения
Мне интересно об этом из-за проблем области. Например, рассмотрим код
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 всегда копировать? В этом случае это, кажется, работает, поэтому я убежден, что return делает копию. Если он копирует, будет ли он копировать в каждом случае?
10 ответов:
да, в этом случае будет снять копии. Если вы измените объявление функции следующим образом:
subline_t &subline(int x1, int x2, int id) {тогда копия не будет сделана. Однако в вашем конкретном случае было бы недопустимо возвращать ссылку на объект, выделенный в стеке. Проблема заключается в том, что объект будет уничтожен и признан недействительным до того, как вызывающий сможет его использовать.
Это связано с общим Оптимизация Возвращаемого Значения для C++, который может избежать этого фактическая операция копирования в описанном случае. Конечный результат (или должен быть) такой же, как если бы копия была сделана, но вы должны знать об оптимизации. Наличие такой оптимизации может в некоторых случаях изменить наблюдаемое поведение программы.
Он всегда будет возвращать копию.
Если вы хотите избежать снижения производительности копирования объекта при возврате, вы можете объявить указатель, построить экземпляр объекта с помощью new и вернуть указатель. В этом случае указатель будет скопирован, но объект не будет.
в вашем случае он вернет копию
Если ваш код
subline_t& subline(int, int)тогда он вернет ссылку, которая приведет к неопределенному поведению.
Да, для функции, объявленной для возврата a
struct,returnтакой структуры будет копировать его (Хотя компилятор уполномочен оптимизировать копию прочь, по существу, в тех случаях, когда он может доказать, что оптимизация семантически безвредна, вы можете рассуждать "как будто" копирование было гарантировано).однако, так как вы сделал пометьте это как C++, а не C, почему бы не поставить ваш
structс конструктором, а не...? Кажется более ясным и прямым...!- )
да, возврат является копией
subline_t subline(int x1, int x2, int id) { subline_t t = { x1, x2, id }; return t; }Если вы поставите referencer, то его не скопировать
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 }
он возвращает копию, которая является то, что вы хотите, чтобы это сделать. Изменение его для возврата ссылки приведет к неопределенному поведению в присвоении строки.
однако идиоматический способ сделать это в C++ - это использовать конструкторы и списки назначений. Это лучше инкапсулирует код и структуры данных и позволяет избежать множества промежуточных объектов, которые компиляторы могут свободно создавать/уничтожать/копировать.
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. }
объекты разворачиваются в C++ сделано по значению, а не по ссылке.
ссылка на 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
возвращаемый класс или структура могут быть скопированы или не скопированы, в зависимости от того, использует ли компилятор copy elision. Смотрите ответы на что такое копирование elision и оптимизация возвращаемого значения? короче говоря, будет ли он скопирован или нет, зависит от ряда вещей.
вы можете, конечно, избежать копирования, вернув ссылку. В случае вашего примера возврат ссылки недопустим (хотя компилятор это позволит), потому что локальная структура выделяется в стеке, и поэтому возвращенная ссылка ссылается на освобожденный объект. Однако, если объект был передан вашей функции (непосредственно или как член объекта), вы можете безопасно вернуть ссылку на него и избежать копирования при возврате.
наконец, если вы не можете доверять copy elision и хотите избежать копий, вы можете использовать и возвращать a
unique_ptrвместо ссылки. Сам объект не будет скопирован, хотяunique_ptrсам может или не может быть (опять же, в зависимости от копирования elision!). Копирование/перемещение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не будет компилироваться из-за недостатков языка C++.
просто FYI, так как в этом случае вы используете только структуру(Уре), это то же самое поведение, что и в языке C.
хотя это языковая функция, это рекомендуется его не использовать
Comments