Когда желательна мелкая копия (вместо глубокой)? - PullRequest
10 голосов
/ 28 июля 2010

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

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

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

Ответы [ 9 ]

8 голосов
/ 28 июля 2010

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

4 голосов
/ 28 июля 2010

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

4 голосов
/ 28 июля 2010

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

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

3 голосов
/ 28 июля 2010

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

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

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

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

2 голосов
/ 28 июля 2010

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

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

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

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

2 голосов
/ 28 июля 2010

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

template <typename T>
struct NotNull {

   T * p;

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

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

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

1 голос
/ 28 июля 2010

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

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

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

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

1 голос
/ 28 июля 2010

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

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