Возвращает ли оператор 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   59   2009-10-07 08:15:44

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.
}

структуры subline_t вы определили, да, он всегда будет возвращать копию.

объекты разворачиваются в 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.

хотя это языковая функция, это рекомендуется его не использовать