почему конструктор копирования вызывается, когда мы возвращаем объект из метода по значению. пожалуйста, смотрите мой код ниже, в котором я возвращаю объект из метода, в то время как возвращение элемента управления ударяет конструктор копирования, а затем возвращает. меня не поняли следующие вещи:
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;
}
Конструктор копирования вызывается потому, что вы вызываете по значению, а не по ссылке. Поэтому новый объект должен быть создан из вашего текущего объекта, так как все члены объекта должны иметь одинаковое значение в возвращаемом экземпляре. Потому что иначе вы бы возвращали сам объект, который возвращался бы по ссылке. В этом случае изменение ссылочного объекта также изменит оригинал. Как правило, это не то поведение, которое нужно при возврате по значению.
Я постараюсь ответить на все вопросы сразу.
Поведение, которое вы наблюдаете, связано с тем, как возврат объекта по значению работает в 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(); }
Даже если реализации разрешено исключать копию, жизнеспособный и доступный конструктор копии (или конструктор перемещения, если мы говорим о перемещении) все равно должен присутствовать.
Функция возвращает объект. Следовательно, этот объект должен существовать. Следовательно, этот объект должен быть создан откуда-то. Понятно, что это означает, что должен использоваться один из его конструкторов. Вопрос в том, какой?
Так как вы решили return str;
это инструкция, которая будет использоваться для его создания. Как еще вы могли бы использовать эту инструкцию возврата для создания и возврата объекта и при этом не использовать конструктор копирования? Понятно, что нужно использовать str
инициализировать возвращаемое значение, поэтому вы не собираетесь использовать другую опцию (конструктор без параметров).
ClassA function (ClassA &str)
{
return str;
}
объект str
будет скопирован во временный объект с типом ClassA
для дальнейшего использования. Однако компилятор может опустить его из-за оптимизации.