2009-05-28 6 views
10
class A 
{ 
public: 
    A(const int n_); 
    A(const A& that_); 
    A& operator=(const A& that_); 
}; 

A::A(const int n_) 
{ cout << "A::A(int), n_=" << n_ << endl; } 

A::A(const A& that_) // This is line 21 
{ cout << "A::A(const A&)" << endl; } 

A& A::operator=(const A& that_) 
{ cout << "A::operator=(const A&)" << endl; } 

int foo(const A& a_) 
{ return 20; } 

int main() 
{ 
    A a(foo(A(10))); // This is line 38 
    return 0; 
} 

Выполнение этого кода дает о/р:Почему копия ctor используется в этом коде?

A::A(int), n_=10
A::A(int), n_=20

Очевидно, конструктор копирования не вызывается.

class A 
{ 
public: 
    A(const int n_); 
    A& operator=(const A& that_); 
private: 
    A(const A& that_); 
}; 

Однако, если мы делаем это частный, возникает эта ошибка компиляции:

Test.cpp: In function ‘int main()’:
Test.cpp:21: error: ‘A::A(const A&)’ is private
Test.cpp:38: error: within this context

Почему компилятор жалуется, когда он на самом деле не использовать конструктор копирования?
Я использую GCC версии 4.1.2 20070925 (Red Hat 4.1.2-33)

ответ

12

Core defect 391 объясняет проблему.

В принципе, для текущего стандарта C++ требуется, чтобы конструктор копирования был доступен при передаче временного типа класса в ссылку const.

Это требование будет удалено в C++ 0x.

Логика требует конструктор копирования приходит из этого случая:

C f(); 
const C& r = f(); // a copy is generated for r to refer to 
+0

FYI Я думаю, что это все еще присутствует в C++ 11 ('12.2/1'). –

1

Копия-конструктор не используется, но для того, чтобы компилировать код копировальную-конструктор должен быть доступен.

EDIT: компилятор Комео C++ сообщает следующее:

Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2 
Copyright 1988-2008 Comeau Computing. All rights reserved. 
MODE:strict errors C++ noC++0x_extensions 

"ComeauTest.c", line 38: error: "A::A(const A &)" (declared at line 17), required 
      for copy that was eliminated, is inaccessible 
    A a(foo(A(10))); // This is line 38 
      ^

1 error detected in the compilation of "ComeauTest.c". 

Обратите внимание, что если расширения C++ 0x включены, он отлично компилируется в Comeau C++ компилятор.

+0

Что, черт возьми, Комо нужно скопировать временный объект? Он передан по ссылке! – xtofl

+0

И какую Оптимизацию возвращаемого значения вы имеете в виду? – xtofl

+1

Нет Объект возвращается, поэтому RVO не имеет отношения к использованию конструктора копии. A (10) является rvalue типа A, хотя, и компилятор может выбрать, чтобы взять копию этого, чтобы связать ссылочный параметр. Именно эта потенциальная копия требует, чтобы конструкторы копирования были доступны. –

3

Насколько я вижу, вы не используете конструктор копирования нигде. В заявлении foo(A(10)) вы создаете временный объект класса A и передаете его как const-ссылку на foo. Функция foo возвращает целое число, которое используется при построении объекта a. Поэтому я не вижу, где здесь задействован конструктор копирования и как NRVO входит в картину. Кроме того, я скомпилировал следующий код, сделав его конструктором закрытым и скомпилировав его в VS2008.

using namespace std; 

class A 
{ 
public: 
    A(const int n_); 
private: 
    A(const A& that_); 
    A& operator=(const A& that_); 
}; 

A::A(const int n_) 
{ cout << "A::A(int), n_=" << n_ << endl; } 

A::A(const A& that_) // This is line 21 
{ cout << "A::A(const A&)" << endl; } 

A& A::operator=(const A& that_) 
{ 
    cout << "A::operator=(const A&)" << endl; 
    return *this; 
} 

int foo(const A& a_) 
{ return 20; } 


int main(int argc,char *argv[]) 
{ 
    A a(foo(A(10))); // This is line 38 
    return 0; 

} 
+0

То же самое на VS2005, кстати. – xtofl

+1

@AngryWhenHungry: Кстати, вам не хватало возврата * этого в операторе присваивания. Я надеюсь, что это не ошибка компилятора, которую вы получали :-) – Naveen

+1

Посмотрите ответ Джеймса Хопкина: http://stackoverflow.com/questions/919701/c-why-is-the-copy-ctor-used-in-this -код/​​920118 # 920118. В принципе, привязка временной к константной ссылке * still * требует копирования ctor (в C++ 03). –

0

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

5

стандарт 2003, в §12.2/1, гласит:

Even when the creation of the temporary object is avoided (12.8), all the semantic restrictions must be respected as if the temporary object was created. [Example: even if the copy constructor is not called, all the semantic restrictions, such as accessibility (clause 11), shall be satisfied. ]

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

+0

Но как семантика foo (const A &) диктует использование конструктора копирования? – xtofl

2

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

A original(10); 
foo(original); // does compile 
foo(A(10)); // doesn't compile - needs a copy constructor 
0

При вызове:

foo(A(10)); 

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

При вызове:

{ 
    A original(10); 
    foo(original); 
} 

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

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

1

В выражении:

A a(foo(A(10))); 

Результат подвыражении A(10) является Rvalue типа A. (5.2.3 [expr.type.conv])

При инициализации константной ссылки от RValue компилятор может создать временный из RValue и связать, что в качестве ссылки. Даже если он не хочет, конструктор копирования должен быть доступен. (8.5.3 [decl.init.ref]) Это было бы не так, если бы ссылка была инициализирована с ссылочной совместимостьюlvalue, где обязательна прямая привязка.

Поскольку foo принимает свой параметр по ссылке, а не по значению, копия не предназначена для инициализации самого аргумента.

foo возвращает int, поэтому здесь нет копии A.

a прямо инициализируется из int, возвращаемого foo, поэтому здесь нет копии A.

Смежные вопросы