Странный конструктор копирования

С помощью следующей программы C ++:

#include <memory>
#include <iostream>

using namespace std;

struct my_class{
int value;

my_class(int id): value(id){
cout<<"constructing "<<id<<endl;
cout<<"address is "<<static_cast<const void *>(this)<<endl;
}

my_class(const my_class & a){
cout<<"construct copying "<<a.value<<endl;
cout<<static_cast<const void *>(this)<<"<-"<<static_cast<const void *>(&a)<<endl;
}

my_class operator=(const my_class & a){
cout<<"assignment copying "<<a.value<<endl;
this->value = a.value;
cout<<static_cast<const void *>(this)<<"<-"<<static_cast<const void *>(&a)<<endl;
return *this;
}

~my_class(){
cout<<"deleting "<<this->value<<endl;
cout<<"address is "<<static_cast<const void *>(this)<<endl;
}
};

my_class f(){
cout<<"==in f=="<<endl;
my_class temp(2);
cout<<"==out f=="<<endl;
return temp;
}

int main(){
cout<<"==in main=="<<endl;
my_class a(1);

a = f();

a.value++;
cout<<"==out main=="<<endl;
return 0;
}

Я получил следующий результат:

====

==in main==

constructing 1

address is 0x28ff04

==in f==

constructing 2

address is 0x28ff0c

==out f==

assignment copying 2

0x28ff04<-0x28ff0c

construct copying 2

0x28ff08<-0x28ff04

deleting 2686868

address is 0x28ff08

deleting 2

address is 0x28ff0c

==out main==

deleting 3

address is 0x28ff04===

Может кто-нибудь объяснить мне, что происходит с объектом по адресу «0x28ff08» и связанной с ним копией, создаваемой из объекта по адресу «0x28ff04»? Я действительно не понимаю, почему конструктор копирования вызывается здесь.


Я не знаю, правильно ли я понял, поэтому хочу более подробно объяснить это. Кто-нибудь найдет мои ошибки, пожалуйста, укажите их.

Во-первых, изображение иллюстрирует детали потока выполнения:
поток выполнения

(1). Создать объект a со значением 1;

(2). Функция вызова f(), Создать объект tempи компилятор обнаруживает, что объект будет возвращен, поэтому он создается непосредственно в стеке вызывающего;

(3). Назначить возвращаемый объект f() (Т.е. temp) для объекта a позвонив operator=() из a;

(4). объект a передается в operator=() в качестве параметра (rvalue) используется то же имя переменной a,

(5). Метод operator=() называется на main::a (lvalue, со злоупотреблением обозначениями), таким образом this в функции указывает на main::a, [!! Это та часть, которая смутила меня];

(6). operator=() меняет значение main::a в aзначение (т. е. от 1 до 2);

(7). Компилятор находит, что возвращаемый тип не является ссылкой, и *this уже существует в main()поэтому он должен скопировать *this вызывая конструктор копирования. Однако конструктор копирования не инициализирует объект, поэтому создается неинициализированный объект.

(8). [!! не совсем уверен насчет этой части] lvalue и результирующий объект — это один и тот же объект, поэтому ни один объект действительно не возвращается из-за оптимизации.

(9). Скопированный объект уничтожается, согласно @Mike Seymour, этот объект создается, потому что компилятор не может его опустить, потому что и конструктор, и деструктор действительно что-то делают (например, выводят значение и адрес).

(10). При выходе operator=()объект a уничтожен

(11). При выходе main()объект main::a наконец уничтожен.

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

0

Решение

Конструктор копирования вызван, потому что ваш оператор присваивания возвращает копию *this, Как уже отмечали другие, оператор присваивания должен возвращать ссылку, а не копию; как для избежания ненужного копирования, так и для обеспечения возможности оператора цепочки.

Возможно, вопрос, который вы пытаетесь задать, заключается в следующем: почему при возврате значения из оператора присваивания требуется копия, а при возврате из f() не делает?

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

operator=() возвращает копию постоянного объекта. Поскольку исходный объект все еще будет существовать и должен быть отделен от возвращаемого значения, здесь необходима копия.

Или, возможно, вы пытаетесь спросить, почему компилятор не удаляет копию, поскольку скопированный объект никогда не используется? Это потому, что вы дали конструктору и деструктору побочные эффекты, а компилятору не разрешено их устранять.

2

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

Это потому, что ваш оператор присваивания возвращает копию объекта. Вот:

 my_class operator=(const my_class & a)

используйте ссылку вместо:

 my_class& operator=(const my_class & a)
4

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