Копирует значения возвращаемой инструкции

Мне интересно об этом из-за проблем с областью. Например, рассмотрим код

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.

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