2010-02-06 3 views
15

Я немного смущен относительно механики конструктора копирования. Исправьте меня, если я ошибаюсь:Могу я вызвать конструктор копирования явно?

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

Кроме того, можно назвать

Object * obj = new Object(&anotherObject); 

создать копию anotherObject?

+1

Ваша терминология не должна предполагать, что 'anotherObject' создает копию себя .. объект, который создается после того, как новый будет создание копии' anotherObject'. –

+5

@ Хассан: Не изменяйте значение вопроса, не спрашивая OP. Это важное различие. '& anotherObject' является указателем, а не ссылкой. –

+0

«невозможно сказать», что 'new object (& anotherObject)' будет создавать копию другого объекта неявно (что и предлагает формулировка). Для того чтобы этот оператор сохранялся, синтаксис нуждается в настройке. –

ответ

26

Нет, если функция взять ссылку:

void f1(Object & o); // call by reference 

то копия не сделана. Если какая-либо функция принимает значение:

void f2(Object o); // call by value 

затем копия создается компилятором с использованием конструктора копирования.

И да, когда вы говорите:

Object * obj = new Object(anotherObject); // not &anotherObject 

конструктор копирования используется в явном виде (в предположении, anotherObject имеет тип Object.) Там нет ничего магического в использовании new здесь, однако, - в этом случае:

Object obj2(anotherObject); 

также используется копировальный аппарат.

+1

", тогда копия создается компилятором с использованием конструктора копирования." - он может использовать конструктор move, а также это сценарий копирования, поэтому, возможно, даже никакого конструктора вообще нет. –

7

Если метод принимает ссылку на объект как параметр, конструктор копирования не будет вызываться. Если это так, то вызов самого конструктора копирования привел бы к бесконечному циклу (поскольку он принимает ссылку в качестве аргумента).

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

+0

Собственно, аргумент copy-constructor не является твердым. Стандарт языка допускает в некоторых случаях необязательное копирование и явно указывает, что реализация должна убедиться, что в случае экземпляра-копии нет бесконечной рекурсии в качестве примера (см. Сноску 93 в C++ 03) – AnT

+0

@AndreyT: Интересно. Во всяком случае, это не меняет ситуацию в этом случае, так как мы говорим о * не * копировании в случае ссылки, что довольно верно. –

+0

Ну, часть стандарта, о которой я говорил, на самом деле связана с инициализацией ссылки, и она явно разрешает копирование в некоторых ситуациях (в случае инициализации const-ссылки). Конечно, компиляторы обычно не участвуют в диком необоснованном копировании, но известны примеры компилятора, создающего странные нелогичные (но все же законные) копии. – AnT

1

Нет в обоих случаях. В первом случае передается ссылка на этот объект и копия не создается. Во втором случае вы передаете указатель на конструктор object, поэтому копия не создается. Таким образом, объект должен иметь конструктор (не конструктор копирования), который является чем-то вроде object(anotherClass*)

1

Copy конструктор вызывается только при прохождении по значению, не по ссылке. По ссылке не требуется копирование (это часть ссылок для!), Поэтому не вызвал конструктор копирования.

3

То, что вы делаете вызов метода, здесь не имеет значения. Инициализация ссылочного параметра во время вызова функции ничем не отличается от инициализации автономной ссылки и определяется теми же правилами.

Правила инициализации ссылок немного сложны, но в нижней строке указано, что если инициализатор является lvalue (аргумент в вызове метода в вашем случае), а тип ссылки такой же, как тип инициализатор (т. е. тип параметра совпадает с типом аргумента), тогда ссылка будет связана напрямую. То есть копия не создается.

Object a; // class type 
Object &r = a; // no copying 
const Object &cr = a; // no copying 

Если эти требования не выполняются (например, если инициализатор является rvalue, например), то все зависит. В некоторых случаях копирование может и произойдет. Например

const Object &tr = Object(); 

может интерпретироваться компилятором, как

const Object &tr = Object(Object(Object(Object()))); 

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

Классический пример, который часто мешает спор о действительности копировального поведения компилятора ссылка инициализация в выражениях, как в следующем одном

Object a; 
const Object &r = <some condition> ? a : Object(); 

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

+0

вы уверены в этой бесконечной глубине? C++ 03 8.5.3 говорит, что существует только два случая: (a) «Ссылка привязана к объекту, представленному rvalue (см. 3.10), или к под-объекту внутри этого объекта» и (b) « Создается временный тип «cv1 T2» [sic], и вызывается конструктор, чтобы скопировать весь объект rvalue во временный. Ссылка привязана к временному или к под-объекту во временном ». Заметим, что случай (b) говорит * привязан к *, а не * инициализирован из *, поэтому я не вижу, как это (б) разрешает больше, чем одно дополнительное временное. –

+0

Конечно, C++ 14 (который вышел после того, как ваш ответ был написан) разрешает только случай (a), т. Е. Больше не существует временных объектов, кроме 'Object()'. Я не проверял формулировку C++ 11, хотя у ISTR был дефект относительно инициализации ссылок из rvalues. –

0

да с помощью размещения нового, как так:

Object dstObject; 
new(&dstObject) Object(&anotherObject); 
Смежные вопросы