Похоже, вы не знаете о конструкторе копирования и назначении копии. Давайте сначала рассмотрим обе концепции в отдельности, и тогда я приду к вашему вопросу. Ответ немного долго, так что будьте терпеливы :)
Copy Constructor
Здесь я не буду объяснять, как написать конструктор копирования, но когда конструктор копирования называется и когда это не , (Если вы хотите узнать, как написать конструктор копирования, см. this)
Конструктор копирования является специальным конструктором для создания нового объекта в качестве копии существующего объекта.(Это называется всякий раз, когда есть необходимость сделать копию существующего объекта)
Эти сценарии, когда конструктор копирования будет называться, чтобы сделать копию существующего объекта:
Инициализация объекта с некоторыми ранее созданного объекта:
SomeClass obj;
// ...
SomeClass anotherObj = obj; // here copy constructor will be called.
Престола, SomeClass obj;
заявление s подразумевает создание объекта (здесь будет вызываться default constructor, чтобы создать объект). Второй оператор SomeClass anotherObj = obj;
создает экземпляр объекта, инициализированного значениями obj
(существующий объект), поэтому здесь будет вызываться конструктор копирования. Кроме того, можно инициализировать объект с существующим объектом таким образом: SomeClass anotherObj(obj);
(Это утверждение эквивалентно SomeClass anotherObj = obj;
)
Кроме:
При инициализации с некоторыми RValue выражением. например
SomeClass someObject = aObject + anotherObject;
В этом случае движение конструктор будет называться. Смотрите, What are move semantics?
Передача объекта по значению некоторой функции (см Passing arguments by value):
Зе, следующий фрагмент кода, при этом функция doSomething
принимает объект в качестве параметра по величине:
void doSomething(SomeClass someObject)
{
// ...
}
Есть некоторые случаи, когда необходимо будет сделать копию переданного аргумента в объекте параметра someObject
, который я перечислил, когда будет необходимо сделать копию и когда не будет необходимости.
Посмотрите на следующий фрагмент кода:
SomeClass someObject;
// ...
doSomething(someObject); // here copy constructor will be called.
Оператор SomeClass someObject;
просто someObject
по создание экземпляра вызова default constructor.
Второе заявление doSomething(someObject);
вызывает функцию doSomething
, ранее показанную, передав someObject
в качестве аргумента. Это тот случай, когда необходимо передать копию someObject
, чтобы перейти к функции.
Кроме:
Similiary, если мы называем doSomething
с некоторыми RValue выражения, он будет вызывать двигаться конструктор вместо конструктор копирования.
Возвращение объекта из функции по значению:
Давайте посмотрим на следующее определение doSomething
SomeClass doSomehing()
{
SomeClass someObject;
// ...
return someObject;
}
В приведенной выше функции doSomething
, объект SomeClass
создается и после выполнения некоторой задачи объект возвращается функцией, в этом случае будет создана и возвращена копия someObject
.
Кроме:
Similiary, если doSomething
возвращает некоторые выражение Rvalue, он будет вызывать двигаться конструктор вместо конструктор копирования.
Copy Assignment
Копия Назначение обычно путают с конструкцией копирования, давайте посмотрим на то, как он отличается от конструкции копирования:
SomeClass someObject;
// ...
SomeClass anotherObject;
// ...
anotherObject = someObject; // here copy assignment operator will be called.
Первый два заявления только создают someObject
и anotherObject
, видите ли, третий статет nt фактически вызывает оператор присваивания копии и не конструктор копирования.
Конструкторы вызываются только при создании какого-либо нового объекта. А в случае anotherObject = someObject;
оба объекта уже созданы, поэтому вызов конструктора копирования не будет.Вместо того, чтобы оператор присваивания копии будет называться (чтобы увидеть, как перегрузить оператор присваивания копировального см this)
Теперь давайте посмотрим на фрагмент кода:
A *p=new A();
A *q=new A();
*p=*q;
В первом заявлении A *p=new A();
по умолчанию будет создан конструктор по умолчанию для создания объекта (в этом случае новый объект будет создан в куче), а p
будет инициализирован адресом вновь созданного объекта (как p
является pointer)
Похожего дело со вторым утверждением A *q=new A();
(Это создает другой объект и q
будет инициализирован с вновь созданным объектом)
Теперь, третье заявление: *p = *q;
(здесь *
является Dereference operator)
Чтобы понять, что делает третий оператор, давайте посмотрим на некоторые указатели и удалим их, чтобы получить фактический объект, на который они указывают.
int someVariable = 5;
int *somePointer = &someVariable;
// ...
*somePointer = 7;
Давайте попробуем понять выше фрагмент кода: someVariable
создается и инициализируется со значением 5
, то somePointer
создается и инициализируется с адресом someVariable
.
Теперь последнее заявление *somePointer = 7;
, оно фактически отменяет ссылку на somePointer
и путем де-ссылки, оно получит переменную, на которую она указывает. (поэтому он получит someVariable
), а затем он назначает 7
. Таким образом, после этого заявления, значение someVariable
«s станет 7
Давайте еще один пример:
int* somePointer = new int;
int* anotherPointer = new int;
// ...
*somePointer = 5;
*anotherPointer = 7;
// ...
*somePointer = *anotherPointer;
Во-первых, somePointer
будет создан и инициализирован с адресом динамически распределяемой int
переменной (будет выделена в куче , см. Dynamic Allocation in c++), аналогично, anotherPointer
будет инициализирован адресом другой динамически назначенной переменной.
Затем он назначая 5
первой переменной (которая в настоящее время указываемой somePointer
) и 7
второй переменной (которая в настоящее время указываемой anotherPointer
)
Теперь, последнее утверждение будет представлять интерес , *somePointer = *anotherPointer;
, в этом заявлении *somePointer
де-ссылки и получение первой переменной (значение которой было 5
), а *anotherPointer
- удаление ссылок и получение второй переменной (значение которой равно 7
), и она назначает вторую переменную первой переменная, что приводит к изменению значения первой переменной до 7
.
Теперь давайте посмотрим на ваш *p=*q;
заявлении (p
указывал на первый объект A
и q
указывал на второй объект A
, как динамически выделяемой), *p
будет разыменовать p
и получить первый object, *q
будет разыменовывать q
и получить второй объект, а затем второй объект будет скопирован в первом объекте, и если вы видите, новый объект не создается в *p=*q;
, и создается только значение второго объекта в первый объект, поэтому оператор назначения копирования будет вызываться здесь, а не конструктор копирования.
Другое дело
Вы должны отменить выделять динамически выделенную память, вы заимствованные с помощью new
оператора:
delete p;
delete q;
Вы должны добавить эти две строки в конце вашей программы, так избегать Memory Leak.
You «Дайвинг слишком глубоко. Обязательно сначала поймите основы. Ситуация такая же, как в 'int a;' 'int * p = & a, * q = & a;' '* p = * q;' –
@KerrekSB Но в коде OP 'new A()' и 'new A() 'производят разные экземпляры, тогда как ваша аналогия использует единственный экземпляр' int a'. Я думаю, что лучшей параллелью было бы: ** 'int a1 = 5, a2 = 10;' int * p = &a1; '' int * q = &a2; '' * p = * q; '** –
Для любого указателя' tp', который имеет тип 'T *', выражение '* tp' будет разыменовывать этот указатель, оценивая значение типа' T', на которое указывает 'tp'. Итак, вы можете прочитать это как «значение, на которое указывает« p »= значение, на которое указывает« q »;' –