Почему конструктор копии С++ должен использовать объект const? - программирование
Подтвердить что ты не робот

Почему конструктор копии С++ должен использовать объект const?

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

class ABC {
public:
    int a;
    int b;
    ABC(const ABC &other)
    { 
        a = other.a;
        b = other.b;
    }
}

Мой вопрос в том, что произойдет, если аргумент конструктора копирования не const:

class ABC
{
    public:
    int a;
    int b;
    ABC(ABC &other)
    { 
        a = other.a;
        b = other.b;
    }
}

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

4b9b3361

Ответ 1

  • Логически, нет смысла модифицировать объект, из которого вы хотите сделать копию, хотя иногда это может иметь некоторый смысл, например, ситуации, когда вы хотите сохранить количество времени объект был скопирован. Но это может работать с переменной-членом mutable, которая хранит эту информацию и может быть изменена даже для объекта const (а вторая точка будет оправдывать этот подход).

  • Вы хотели бы иметь возможность создавать копии объектов const. Но если вы не передаете свой аргумент с помощью спецификатора const, то вы не можете создавать копии объектов const...

  • Вы не можете создавать копии из временной ссылки, поскольку временные объекты имеют значение rvalue и не могут быть привязаны к неконстантным. Для более подробного объяснения я предлагаю статью Herb Sutter по этому вопросу

Ответ 2

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

Ответ 3

Здесь могут потребоваться две причины:

  • Это гарантирует, что вы не случайно "повредите" оригинал при создании копии - это хорошо, потому что вы не хотите, чтобы ваш исходный объект был изменен при его копировании!
  • Вы можете передать нечто иное, чем базовый объект, поскольку конструктор принимает ссылку, если это не сам объект, например, выражение.

Чтобы проиллюстрировать второй случай:

 class ABC
    {
       public:
           int a;
           int b;
       ABC(const ABC &other)
       { 
         a = other.a;
         b = other.b;
       }
       ABC operator+(const ABC &other)
       {
           ABC res;
           res.a = a + other.a;
           res.b = b + other.b;
           return res;
       }
    }

  ...
  ABC A;
  a.a = 1;
  a.b = 2;
  ABC B(a+a);

Это не будет компилироваться, если конструктор ABC(ABC &other), так как a+a является временным объектом типа ABC. Но если он ABC(const ABC &other), мы можем использовать временный результат вычисления и все еще передавать его в качестве ссылки.

Ответ 4

Как видно из нескольких других ответов, конструктор копирования, который изменил его аргумент, был бы неприятным сюрпризом. Это, однако, не единственная проблема. Конструкторы копирования иногда используются с аргументами, которые являются временными. (Пример: возврат из функции.) И неконстантные ссылки на временные файлы не летают, как описано в другом месте на SO.

Ответ 5

Если конструктор копирования не указывает его параметр как const, этот фрагмент не будет компилироваться.

const ABC foo;
ABC bar(foo);

Ответ 6

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

const предназначен только для пользователя. Это не существует для фактического исполняемого файла.

Ответ 7

Это не "необходимо" в техническом смысле. У нас даже есть такой зверь прямо в стандарте, хотя он устарел. Следуйте ссылкам для рассуждений.

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

В ожидании вы подумаете дважды, чтобы иметь копию ctor, которая делает иначе. Это удивит пользователей и, вероятно, приведет к ошибкам. И разочарование и шум, просто попробуйте google для "vector of auto_ptr", чтобы увидеть счет.

Остальная часть вопроса может быть "Я клянусь не касаться оригинала в реализации, но хочу другую подпись". Какая подпись тогда? Попробуйте T и T &.

T выпадает, так как требуется, чтобы копия ctor использовалась, и мы реализуем именно это. Рекурсия: см. Рекурсию.

Это оставляет T &. Это действительно будет работать в нескольких случаях. Но просто потерпите неудачу, если ваш исходный объект будет сидеть в форме const или быть временным. Зачем мешать этому разумному делу вообще без дождя?

Ответ 8

В дополнение к фундаментальному предположению о том, что конструкторы копирования не должны изменять исходный экземпляр, в этой статье рассматривается фактическая техническая причина использования const:

http://www.geeksforgeeks.org/copy-constructor-argument-const/

А именно, и я цитирую:

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