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

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

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

Примечание: Мне не важно, на каком языке приведены примеры. Я задаю этот вопрос с точки зрения С++/Java/С#, хотя я думаю, что копирование является языковой агностической концепцией.

Ответ 1

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

Ответ 2

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

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

Ответ 3

Исходя из С++ POV, будет один сценарий, который я буду использовать неглубокую копию: при реализации механизма copy-on-write.

Ответ 4

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 выполнялись объектными методами, но вы хотите открыть элементы, хранящиеся в списке. Таким образом, вы создаете getter, который возвращает неглубокую копию. Скопируйте, потому что вы не хотите, чтобы вызывающий абонент изменял список объектов и неглубоко, потому что вы хотите выставлять объекты из списка, а не их копии.

Ответ 5

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

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

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

Ответ 6

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

template <typename T>
struct NotNull {

   T * p;

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

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

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

Ответ 7

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

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

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

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

Ответ 8

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

Ответ 9

Примечание. Мне не важно, на каком языке приведены примеры. Я задаю этот вопрос с точки зрения С++/Java/С#, хотя я думаю, что копирование является языковой агностической концепцией.

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

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

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