Когда мелкая копия желательна (вместо глубокой копии)?

Кто-то может дать пример ситуации, где мелкая копия необходима?

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

Комментарий: Я не забочусь, в котором языке даны примеры. Я задаю этот вопрос от C++/Java/C# точка зрения, хотя я думаю, копируя, понятие агностика языка.

10
задан Dimitri C. 28 July 2010 в 08:13
поделиться

9 ответов

class Element{
}

class Example {
    private List<Element> elementList = new ArrayList<Element();

    public List<Element> getElementList() {
        return new ArrayList<Element>(this.elementList);
    }

    public void addElement(Element e) {
        elementList.add(e);
    }

    public void removeElement(Element e) {
        elementList.remove(e);
    }
}

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

3
ответ дан 3 December 2019 в 15:34
поделиться

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

Вы можете сохранить мелкую копию, а затем перестроить весь объект из состояния после десериализации.

4
ответ дан 3 December 2019 в 15:34
поделиться

Примечание: мне все равно, на каком языке приведены примеры. данный. Я задаю этот вопрос с точки зрения C ++ / Java / C #, хотя считаю, что копирование - это концепция, не зависящая от языка.

Я думаю, это во многом зависит от языка.

В C ++ копирование играет совсем иную роль, чем в Java / C #. В C ++ я не могу придумать многих случаев, когда имеет смысл неглубокое копирование. Вместо этого вы обычно просто создаете ссылки или указатели на объект. Конструкторы копирования обычно реализуют глубокие копии, потому что в C ++ объект становится владельцем своих членов и отвечает за управление их временем жизни. Поскольку сборщика мусора нет, эта семантика владения становится важной, и вы не можете просто иметь два объекта, указывающие на третий, без особой осторожности (используют ли они подсчет ссылок, чтобы сохранить третий живым? Если нет, то какой из двух объектов владеет этим?)

Я бы даже сказал, что различие между «глубокими» и «мелкими» копиями на самом деле не имеет смысла в C ++. Копия создает все необходимое для работы вновь созданного объекта.Иногда он разделяет бит данных (обычно данные, которые не принадлежат ни одному из объектов), поэтому это может быть не «настоящая» глубокая копия, но и не мелкая, потому что большая часть класс обычно копируется .

1
ответ дан 3 December 2019 в 15:34
поделиться

Как я указал в своем ответе на ваш связанный с этим вопрос, многие языки действительно не имеют концепции поверхностного и глубокого копирования. Однако этот класс в C ++, который не позволяет вам использовать указатель NULL, может быть примером, когда требуется «неглубокая» копия:

template <typename T>
struct NotNull {

   T * p;

   NotNull( T * t ) : p( t ) {}

   T & operator *() { 
       if ( ! p ) {
          throw "null!";
       }
       return * p;
   }
};

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

2
ответ дан 3 December 2019 в 15:34
поделиться

Я считаю, что ситуации, в которых вы бы использовали глубокое копирование, отличаются для C ++ и Java.

  • В C ++ вы можете использовать глубокое копирование, чтобы избежать сложных проблем с управлением памятью или упростить реализацию многопоточного приложения.

  • В Java глубокое копирование не требуется по этим причинам. Поскольку оба языка являются сборщиками мусора, для освобождения структур данных нет необходимости проделывать все возможное. Так что для упрощения проблемы нет необходимости в глубоком копировании. Точно так же Java имеет встроенную поддержку для синхронизации доступа нескольких потоков к совместно используемым структурам данных.

В большинстве случаев глубокое копирование в Java не требуется при условии, что структуры данных вашего приложения хорошо спроектированы.

2
ответ дан 3 December 2019 в 15:34
поделиться

Исходя из C ++ POV, я буду использовать неглубокую копию в одном сценарии: при реализации механизма копирования при записи.

4
ответ дан 3 December 2019 в 15:34
поделиться

Мелкие копии сделать быстрее, что часто бывает желательно по очевидным причинам. Совершенно очевидно, что в конечном итоге поверхностное копирование - это просто копия ссылки на исходный объект. Если вы не мутируете объект и можете гарантировать, что он не будет изменен другими способами, пока вы работаете с ним, то чем более мелкой будет копия, тем лучше.

1
ответ дан 3 December 2019 в 15:34
поделиться

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

8
ответ дан 3 December 2019 в 15:34
поделиться

Если вы посмотрите на паттерны проектирования Gang of Four, там есть паттерн под названием FlyWeight. Вот цитата из Википедии:

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

Это было бы приемлемым использованием неглубокой копии.

3
ответ дан 3 December 2019 в 15:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: