Конструктор/оператор/функция копии должен ясно дать понять, какой вариант копии это реализует?

Вчера я задал вопрос о копировании объектов в C#, и большинство ответов сфокусировалось на различии между глубокой копией и мелкой копией и тем, что это должно быть ясно дано понять, какой из обоих вариантов копии реализует данный конструктор копии (или оператор или функция). Я нахожу это нечетным.

Я записал много программного обеспечения в C++, язык, который в большой степени полагается на копирование, и мне никогда не были нужны несколько вариантов копии. Единственный вид операции копии, которую я когда-либо использовал, является тем, который я называю "глубокой копией". Это делает следующее:

  • В случае, если объект имеет владение по членской переменной (cf. состав), это копируется рекурсивно.
  • В случае, если объект не имеет никакого владения по членской переменной (cf. агрегирование), только ссылка копируется.

Теперь, мой вопрос является трехкратным:

13
задан Community 23 May 2017 в 11:53
поделиться

2 ответа

Большинство программистов на C ++ не используют термины «неглубокая копия» и «глубокая копия» по той очень веской причине, что обычно существует только один способ скопировать объект. Это особенно верно в C ++, потому что компилятор использует конструктор копирования во многих ситуациях, когда программист может сказать ему, какой конструктор копирования использовать - например:

void f( std::string s );

нет способа сообщить компилятору, как копировать строку.

2
ответ дан 2 December 2019 в 00:57
поделиться

Объекту нужно только скопировать то, что ему нужно скопировать. Хотя этот вопрос помечен как независимый от языка, и вы упомянули C ++, я предпочитаю объяснять в терминах C # (поскольку это то, с чем я наиболее знаком). Однако концепции похожи.

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

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

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

Хорошо, я соврал, я воспользуюсь C ++, так как он лучше всего объясняет, что я имею в виду.

class MyClass {
    int foo;
    char * bar;
    char * baz;

public: MyClass(int f, char * str) {
        this->foo = f;
        bar = new char[f];
        this->baz = str;
    }
};

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

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

И, конечно же, foo - это просто число. Просто скопируйте его, больше не о чем беспокоиться :)

В общем, чтобы ответить на ваши вопросы напрямую:

  1. В 99% случаев - нет.Есть только один способ копирования, который имеет смысл. Однако то, что это значит, варьируется.
  2. Не прямо. Задокументировать это - хорошая идея, но все внутреннее должно оставаться внутренним.
  3. Просто «Глубокая копия». Вам следует (Edit: ALMOST) никогда не пытаться клонировать объект или указатель, который вы не контролируете, так что это исключено из правил :)
5
ответ дан 2 December 2019 в 00:57
поделиться
Другие вопросы по тегам:

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