2010-04-17 3 views
45

Можно создать дубликат:
What is the difference between a deep copy and a shallow copy?Deep копия против Shallow Copy

В чем разница между глубокой и мелкой копией. Какой тип копии выполняет конструктор копирования?

+2

Дубликат http://stackoverflow.com/questions/184710/what-is-the-difference-between-a-deep-copy-and-a-shallow-copy –

+0

1-й вопрос - это дубликат, но я могу 2-й, хотя это может быть, потому что это не указано четко. @Ankur: в вашем втором вопросе вы спрашиваете о конструкторе копии по умолчанию? – outis

+1

Термины deep vs notow copy обычно не используются в C++, так как они не очень хорошо отображают язык. В Java и нескольких других языках это различие более полезно из-за их основанной на ссылках семантики, делая в большинстве случаев неглубокую копию неизбежной. В C++, где объекты копируются по значению, истинные мелкие копии встречаются очень редко, но конструктор копии по умолчанию не будет реализовывать глубокую копию. Термины просто не имеют смысла в C++ – jalf

ответ

10

Ключевым примером этого является массив указателей на структуры или объекты (которые изменяются).

A мелкая копия копирует массив и поддерживает ссылки на исходные объекты.

A глубокая копия будет копировать (клонировать) объекты, чтобы они не имели никакого отношения к оригиналу. Неявным в этом является то, что сам объект сильно скопирован. Это становится все труднее, потому что нет никакого реального способа узнать, было ли что-то глубоко скопировано или нет.

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

Для ознакомления с подробными сведениями и пояснениями вы можете ознакомиться со статьей Constructors and destructors.

Конструктор копирования по умолчанию неглубокий. Вы можете сделать свои собственные конструкторы копий глубокими или неглубокими, в зависимости от ситуации. См. C++ Notes: OOP: Copy Constructors.

+3

Это должен быть * массив из ** указателей на ** изменяемые объекты * –

+0

Хорошим примером является Boost :: GIL, где представления представляют собой мелкие копии объектов изображения (контейнеры пикселей). Локальные/временные копии пикселей создаются при доступе через объект вида. – jiggunjer

46

Мелкие копии:

Некоторые члены копии могут ссылаться на одни и те же объекты, что и оригинал:

class X 
{ 
private: 
    int i; 
    int *pi; 
public: 
    X() 
     : pi(new int) 
    { } 
    X(const X& copy) // <-- copy ctor 
     : i(copy.i), pi(copy.pi) 
    { } 
}; 

Здесь pi член оригинала и скопировать X объект как точка то же самое int.


Deep копия:

Все члены оригинала клонируют (рекурсивно, если это необходимо). Там нет общих объектов:

class X 
{ 
private: 
    int i; 
    int *pi; 
public: 
    X() 
     : pi(new int) 
    { } 
    X(const X& copy) // <-- copy ctor 
     : i(copy.i), pi(new int(*copy.pi)) // <-- note this line in particular! 
    { } 
}; 

Здесь pi члена исходного и скопированных X объекта будет указывать на различные int объектов, но оба из них имеют одинаковое значение.


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

Исправление: Несколько комментариев ниже правильно указал, что это неправильно сказать, что конструктор копирования по умолчанию всегда выполняет неполную копию (или глубокую копию, по этому вопросу). Независимо от того, создает ли конструктор копии типа мелкую копию или глубокую копию, или что-то среднее между двумя, зависит от комбинации поведения каждого члена в копии; в конце концов, конструктор копии типа члена может быть сделан для того, чтобы делать все, что захочет.

Вот что раздел 12.8, пункт 8 стандарта 1998 года C++ говорит о приведенных выше примерах кода:

неявно определяется скопировать конструктор класса X выполняет почленно копию его подобъектов. [...] Каждый подобъект копируется в методе , соответствующем его типу: [...] [I] f подобъект имеет скалярный тип, используется встроенный оператор присваивания .

+1

Скрытый абзац, похоже, не согласен с вашим смелым утверждением, что конструктор экземпляра по умолчанию делает только мелкие копии. – UncleBens

+0

Что заставляет вас так думать? Я понимаю это следующим образом: члены некоторого типа указателя являются скалярным подобъектом, не так ли?И если вы скопируете указатель, используя встроенный оператор присваивания, это означает, что объект с указателем не будет клонирован, а просто будет называться дополнительным указателем. Поэтому вы получаете мелкую копию. – stakx

+1

@stakx Вы правы, но я думаю, что это иллюстрирует, что термины «глубокая копия» и «мелкая копия» не особенно полезны - на самом деле я никогда не слышал, чтобы их использовали опытные программисты на С ++. – 2010-04-17 10:45:25

2

Глубокая копия буквально выполняет глубокую копию. Это означает, что если ваш класс имеет некоторые поля, которые являются ссылками, их значения будут скопированы, а не сами ссылки. Если, например, у вас есть два экземпляра класса, A & B с полями ссылочного типа и выполнить глубокую копию, изменение значения этого поля в A не повлияет на значение в B. И наоборот. Вещи отличаются от мелкой копии, поскольку копируются только ссылки, поэтому изменение этого поля в скопированном объекте повлияет на исходный объект.

Какой тип копии выполняет конструктор копирования?

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