Почему конструктор копирования вызывается, когда мы возвращаем объект из метода по значению

почему конструктор копирования вызывается, когда мы возвращаем объект из метода по значению. пожалуйста, смотрите мой код ниже, в котором я возвращаю объект из метода, в то время как возвращение элемента управления ударяет конструктор копирования, а затем возвращает. меня не поняли следующие вещи:
1) почему он вызывает конструктор копирования.
2) какой объект неявно передается в конструктор копирования,
3) в какой конструктор объекта копирования будет копироваться содержимое,
4) зачем копировать содержимое объекта при возврате. так что плз помогите.

#include "stdafx.h"#include <iostream>
#include <string>
using namespace std;

class ClassA
{
int a, b;
public:
ClassA()
{
a = 10;
b = 20;
}
ClassA(ClassA &obj)
{
cout << "copy constructor called" << endl;
}
};

ClassA function (ClassA &str)
{
return str;
}

int main ()
{
ClassA str;
function(str);
//function(str);
return 0;
}

6

Решение

Конструктор копирования вызывается потому, что вы вызываете по значению, а не по ссылке. Поэтому новый объект должен быть создан из вашего текущего объекта, так как все члены объекта должны иметь одинаковое значение в возвращаемом экземпляре. Потому что иначе вы бы возвращали сам объект, который возвращался бы по ссылке. В этом случае изменение ссылочного объекта также изменит оригинал. Как правило, это не то поведение, которое нужно при возврате по значению.

1

Другие решения

Я постараюсь ответить на все вопросы сразу.

Поведение, которое вы наблюдаете, связано с тем, как возврат объекта по значению работает в C ++. Во-первых, временный объект создается копией (или движением в C ++ 11) из значения, возвращаемого вашей функцией. Затем, если это возвращаемое значение используется для инициализации другого объекта, например, в:

Class c = fxn();

Предмет c создается из копии (или создается в C ++ 11) из этого временного объекта.

Тем не менее, реализация может обходить молчанием один (в вашем конкретном случае) или оба этих вызова конструктора копирования или перемещения в соответствии с пунктом 12 / 8.31 стандарта C ++ 11, даже если эти конструкторы имеют побочные эффекты и создают возвращаемое значение функции непосредственно в c:

Когда определенные критерии выполнены, реализация может опустить конструкцию копирования / перемещения класса
объект, даже если конструктор выбран для операции копирования / перемещения и / или деструктор для объекта
имеют побочные эффекты
. В таких случаях реализация обрабатывает источник и цель пропущенного копирования / перемещения.
операция, как просто два разных способа обращения к одному и тому же объекту, и уничтожение этого объекта
происходит в более поздние времена, когда два объекта были бы уничтожены без оптимизации.122
Такое исключение операций копирования / перемещения, называемое разрешением копирования, допускается при следующих обстоятельствах (которые
могут быть объединены для устранения нескольких копий)
:

— в return оператор в функции с типом возвращаемого класса, когда выражение является именем
энергонезависимый автоматический объект (кроме параметра функции или предложения catch) с тем же CV-неквалифицированным
type в качестве типа возврата функции, операция копирования / перемещения может быть опущена путем конструирования
автоматический объект непосредственно в возвращаемое значение функции

— […]

— когда будет скопирован / перемещен временный объект класса, который не был связан со ссылкой (12.2)
для объекта класса с таким же cv-неквалифицированным типом, операция копирования / перемещения может быть опущена
построение временного объекта непосредственно в цель пропущенного копирования / перемещения

— […]

Причиной, по которой я написал, что в вашем конкретном случае может быть исключен только один из вызовов конструктора копирования или перемещения, является предложение, выделенное жирным шрифтом в первом пуле приведенной выше цитаты стандарта:

[…] (кроме параметра функции или предложения catch) […]

Если вы возвращаете параметр своей функции, копирование исключается.

Также обратите внимание, что подпись вашего конструктора должна быть:

Class(Class const& c)
//          ^^^^^

У вас нет оснований принимать lvalue ссылку на неconst в конструкторе копирования, поскольку вы не собираетесь изменять объект, с которого копируете.

Хуже того, вышесказанное предотвратит конструкцию копирования из значений r (например, временных), поэтому следующий код не будет компилироваться:

Class foo() { return Class(); }

Даже если реализации разрешено исключать копию, жизнеспособный и доступный конструктор копии (или конструктор перемещения, если мы говорим о перемещении) все равно должен присутствовать.

14

Функция возвращает объект. Следовательно, этот объект должен существовать. Следовательно, этот объект должен быть создан откуда-то. Понятно, что это означает, что должен использоваться один из его конструкторов. Вопрос в том, какой?

Так как вы решили return str;это инструкция, которая будет использоваться для его создания. Как еще вы могли бы использовать эту инструкцию возврата для создания и возврата объекта и при этом не использовать конструктор копирования? Понятно, что нужно использовать str инициализировать возвращаемое значение, поэтому вы не собираетесь использовать другую опцию (конструктор без параметров).

3

ClassA function (ClassA &str)
{
return str;
}

объект str будет скопирован во временный объект с типом ClassA для дальнейшего использования. Однако компилятор может опустить его из-за оптимизации.

2
По вопросам рекламы [email protected]