Как выполняется конструктор копирования? - PullRequest
0 голосов
/ 24 апреля 2019

Я пытаюсь понять конструктор копирования в деталях.При этом я сделал следующий пример:

#include<iostream>

class Test
{
private:
        int a;
public:
        /*
        Test(const Test &t)                          // User defined copy constructor
        {
            a = t.a;
        } */
        Test()
        {
                a = 120;
        }
        int display()
        {
                return a ;
        }
        void set(int var)
        {
                a = var;
        }
};

int main()
{
        Test t1;
        std::cout << "t1.a " << t1.display() << std::endl;
        Test t2 = t1;                                           //Default copy constructor is called
        std::cout << "T2.a " << t2.display() << std::endl;
        t2.set(99);                                             //Changing the value
        std::cout << "t1.a " << t1.display() << std::endl;
        std::cout << "T2.a " << t2.display() << std::endl;
        return 0;
}

Я прочитал в Интернете, что конструктор копирования по умолчанию выполняет «мелкое копирование». Так что это означает, что если obj1 = obj2, что я когда-либо изменяю в obj1 или obj2 даже посленазначение должно быть отражено на обоих объектах, так как они указывают на одно и то же местоположение.Но в этом примере, когда я изменяю значение в одном объекте, оно не отражается в другом.Тот же результат получается при использовании определяемого пользователем конструктора копирования.

Может кто-нибудь прояснить эту тему, независимо от того, происходит мелкое копирование или нет!

Спасибо!

Ответы [ 4 ]

3 голосов
/ 24 апреля 2019

Мелкая копия не является чем-то особенным, что вам нужно запомнить, как правило.Вместо этого это просто то, что происходит в результате использования ссылки или указателя.Рассмотрите этот пример:

struct foo { 
     int* x;
};

int a = 4;
foo f{&a};

Здесь x указывает на a, и если вы скопируете f, новые экземпляры x будут указывать на тот же a.Это мелкая копия.Глубокая копия должна учитывать, что не только x, но и то, на что указывает x, является неотъемлемой частью foo и его также необходимо скопировать.В общем, компилятор не может решить, что вы хотите.Является ли x просто ссылкой или то, что x также относится к части foo?Следовательно, то, что вы получаете, является очевидным: копируются только участники, а не то, к чему они могут обращаться.

Теперь, если вы скопируете foo, а затем измените значение, на которое указывает x, это изменит то же самое a.Мелкая копия была сделана.По моему опыту, термины «глубокая и мелкая копия» скорее добавляют путаницу, чем ясность.То, что вы получаете бесплатно, - это копирование всех участников (мелкая или глубокая копия).Только если вам нужно больше (копируйте также умышленно), вам нужно беспокоиться о мелких и глубоких копиях.

TL; DR: в вашем примере нет глубокой / мелкой копии.Для ценностей это различие не имеет смысла.Используйте int*, чтобы увидеть эффект.

2 голосов
/ 24 апреля 2019

Я читал в Интернете, что конструктор копирования по умолчанию делает "мелкое копирование"

Это неправильный способ мышления конструктора копирования.Конструктор копирования по умолчанию просто копирует все элементы в типе, как будто применяет конструктор копирования по очереди к элементам.

Из ссылки:

Еслинеявно объявленный конструктор копирования не удаляется, он определяется (то есть тело функции генерируется и компилируется) компилятором, если используется odr.Для типов объединения неявно определенный конструктор копирования копирует представление объекта (как с помощью std :: memmove).Для типов классов, не являющихся объединениями (класс и структура), конструктор выполняет полную для всех членов копию баз объекта и нестатических членов в порядке их инициализации, используя прямую инициализацию.

Так что это больше похоже на глубокую копию, чем на мелкую копию.

1 голос
/ 24 апреля 2019

Рассмотрим мелкую копию для простого назначения. Таким образом,

Test t2 = t1; 

означает

t2.a = t1.a

Поскольку a является int, если вы измените a с t1, оно не будет отражено в t2. Так что для int мелкая копия действительно является глубокой копией.

Рассмотрим случай a типа int*. Теперь t2.a и t1.a указывают на одни и те же области памяти. Поэтому, если вы измените значение в ячейке памяти t1.a, то же самое будет отражено через t2.a, поскольку они фактически указывают на одно и то же местоположение.

0 голосов
/ 24 апреля 2019

Неявно определенный конструктор копирования класса просто копирует каждый член [class.copy.ctor] / 14 . Копирование элементов в основном означает, что каждый элемент нового объекта (который копируется) инициализируется из соответствующего члена копируемого объекта таким же образом, как если бы вы написали

T member(original.member);

, где T - тип члена, а original - копируемый объект. Если member относится к типу класса, это фактически сводится к вызову конструктора копирования T. Тем не менее, ваш член простой int, который не является типом класса. Нет конструктора копирования для вызова (int не имеет конструктора копирования); int в новом объекте просто инициализируется из int исходного объекта, что сводится к копированию значения оригинального int в новый int & hellip;

Ваш компилятор не делает различий между глубокой копией и мелкой копией, он даже не знает, что должно означать "глубокая копия" или "мелкая копия". На уровне языка не существует такой вещи, как глубокая копия или мелкая копия в C ++. Это просто термины, которые обычно используются программистами для обсуждения различных подходов к копированию объектов, которые логически (но не физически) содержат другие объекты & hellip;

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...