2009-10-13 3 views
6

Bạn có thể giải thích tại sao đoạn mã sau đây không biên dịch không?Lỗi khi có ctor sao chép riêng với toán tử gán công khai

#include <iostream> 

using namespace std; 

class Foo 
{ 
public: 
    Foo() { cout << "Foo::Foo()" << endl << endl; } 
    Foo& operator=(const Foo&) { cout << "Foo::operator=(const Foo&)" << endl << endl; } 
private: 
    Foo(const Foo& b) { *this = b; cout << "Foo::Foo(const Foo&)" << endl << endl; } 
}; 

int main() 
{ 
    Foo foo; 

    foo = Foo(); 
} 

Các lỗi tôi nhận được:

$ g++ -o copy_ctor_assign copy_ctor_assign.cc && ./copy_ctor_assign 
copy_ctor_assign.cc: In function 'int main()': 
copy_ctor_assign.cc:10: error: 'Foo::Foo(const Foo&)' is private 
copy_ctor_assign.cc:17: error: within this context 

Lưu ý: khi tôi loại bỏ các tin: từ khóa mã biên dịch nhưng ctor bản sao không bao giờ được gọi. Vậy tại sao nó sai khi nó riêng tư?

Không chắc chắn nếu điều quan trọng nhưng tôi đang sử dụng:

$ g++ --version 
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44) 
Copyright (C) 2006 Free Software Foundation, Inc. 
+1

FWIW: Mã không đồng mpile nếu bạn gán một đối tượng Foo được tạo trước đó thay vì một đối tượng tạm thời. I E. 'foo = bar;' thay vì 'foo = Foo();'. – sepp2k

Trả lời

5

Bạn đang khởi tạo một tài liệu tham khảo từ tạm thời.
Trạng thái chuẩn:
Tạm thời phải được khởi tạo (8.5.3 par 5) "bằng cách sử dụng quy tắc cho khởi tạo sao chép không tham chiếu (8.5)".

Việc xây dựng bản sao được xóa tạm thời (được phép theo tiêu chuẩn. 12.8 par 5).
Tuy nhiên, tiêu chuẩn nêu rõ (12.2 par 1):
"Ngay cả khi việc tạo đối tượng tạm thời được tránh (12.8), tất cả các hạn chế ngữ nghĩa phải được tôn trọng như thể đối tượng tạm thời được tạo. nếu các nhà xây dựng bản sao không được gọi, tất cả các hạn chế ngữ nghĩa, chẳng hạn như khả năng tiếp cận (khoản 11), sẽ được no nê.]"

(còn, khi tìm kiếm báo giá ngay, thấy điều này duplicate :)

Chỉnh sửa: thêm vị trí có liên quan từ tiêu chuẩn

+0

Câu trả lời này là chính xác, nhưng bạn trích dẫn phần sai của '8.5.3 para 5' (trong trường hợp của chúng tôi, chúng tôi có các loại lớp và các loại tương thích tham chiếu, do đó, * các dấu * trước đó cần được thực hiện). Điều quan trọng là trước đó và nó nói liệu sao chép hay không được thực hiện xác định và sau đó "Các nhà xây dựng sẽ được sử dụng để làm cho bản sao sẽ được gọi cho dù bản sao thực sự được thực hiện." Đối với C++ 0x, việc triển khai không được phép sao chép nữa và sẽ không yêu cầu một trình tạo bản sao nữa. –

+0

Tôi đã chỉnh sửa :) cảm ơn –

+0

Cảm ơn bạn, tôi đã học được điều gì đó mới mẻ hôm nay. – sdumi

1

Sao chép ctor được gọi khi:

  1. đi qua một đối tượng theo giá trị như tham số để một hàm,
  2. trả lại một đối tượng từ một hàm.

Vì vậy, bạn chắc chắn đang thực hiện một hoặc cả hai trường hợp này ở đâu đó trong mã của bạn. Bạn nên đặt Copy Ctor là public hoặc tránh 2 trường hợp trước đó.

+0

Anh ấy đã làm. Cố gắng biên dịch mã của anh ấy. Lỗi được nêu ra (không có bất kỳ mã bổ sung nào) –

0

Sao chép constructor sẽ được gọi nếu bạn viết

Foo foo; // normal constructor 
Foo foo1(foo); //copy constructor 

Trong trường hợp của bạn, đầu tiên các nhà xây dựng mặc định được gọi và sau đó các nhà điều hành = phương pháp.

+0

Vậy tại sao mã của anh ấy không biên dịch? – sepp2k

+0

Có lẽ mã của anh ta không biên dịch với Werror? ;) – UncleBens

3

Giả sử rằng mã bạn đã đăng là mã duy nhất trong dự án, và không có đi qua bí mật của Foos bởi giá trị xảy ra ở bất cứ đâu, tất cả tôi có thể hình dung là gcc là tối ưu hóa

Foo foo; 
foo = Foo(); 

để

Foo foo = Foo(); 

... đó là không lành mạnh, như là hình thức đầu tiên là một mặc định-xây dựng và chuyển nhượng, trong khi thứ hai là tương đương với

Foo foo(Foo()); 

... rõ ràng là bản sao. Nếu tôi là đúng, các nhà xây dựng bản sao không được chạy bởi vì GCC có thể tối ưu hóa tạm thời dư thừa; điều này được cho phép bởi thông số C++.

Nói chung, không phải là một ý tưởng hay khi có các toán tử gán và sao chép các hàm tạo ở các mức bảo vệ khác nhau; như bạn đã thấy, kết quả có thể không trực quan.

+0

gcc không thể tối ưu hóa các nhà xây dựng như vậy, vì chúng có tác dụng phụ ('cout's). Nếu gcc làm điều đó, đó là một lỗi. – CAdaker

+0

@CAdaker: nope. Loại bỏ các thời gian chờ dư thừa là một trường hợp đặc biệt và tiêu chuẩn C++ cho phép xây dựng bản sao eliding một cách rõ ràng trong những trường hợp như vậy. –

+0

Ngay cả khi các trạng thái tạm thời có các nhà xây dựng và các nhà hủy không tầm thường? Điều đó nghe hoàn toàn điên rồ. – CAdaker

4

Mã đó biên dịch với gcc 4.3.3 và 4.4.1. Có lẽ đó chỉ là một lỗi trong gcc 4.1?

+0

Bạn có thể thử biên dịch lại trong các phiên bản này bằng cách sử dụng -Wall? Cảm ơn –

+0

Tôi nhận được cảnh báo về toán tử = không trả lại giá trị, nhưng không có gì khác. – CAdaker

+0

Nó không thành công đối với tôi: sử dụng g ++ (GCC) 3.4.4 –

-1
#include <iostream> 

using namespace std; 

class Foo 
{ 
public: 
    Foo() { cout << "Foo::Foo()" << endl << endl; } 
    Foo& operator=(const Foo&) { cout << "Foo::operator=(const Foo&)" << endl << endl; } 
    Foo(const Foo& b) { *this = b; cout << "Foo::Foo(const Foo&)" << endl << endl; } 
}; 

int main() 
{ 
    Foo f1;// default constructor called 

    Foo f2 = f1; //copy constructor called 
} 

Kiểm tra này, trong Foo f2=f1; (f2 được tạo ra sử dụng bản sao constructor)

+0

Bạn đang cố gắng nói gì trong đoạn mã trên? Câu hỏi đã được hỏi tại sao nó nhận được lỗi biên dịch khi hàm tạo bản sao là riêng tư. Bạn vừa đưa ra một ví dụ về constructor mặc định và copy constructor. – Jagannath