2011-08-25 59 views
8

Trong cuốn sách Lập trình Generic và STL (phiên bản Trung Quốc), nó nói:hàm tạo hoặc sao chép hàm tạo?

X x = X() sẽ gọi constructor sao chép.

Có vẻ hơi lạ với tôi. Và tôi viết một chương trình thử nghiệm như thế này

#include <iostream> 

class Test { 

public: 

    Test() { 
     std::cout << "This is ctor\n"; 
    } 

    Test(const Test&) { 
     std::cout << "This is copy-ctor\n"; 
    } 

}; 

int main(int argc, char** argv) 
{ 

    Test t = Test(); 
    return 0; 
} 

Đầu ra là "Đây là ctor". ok, bây giờ tôi đang bối rối, đó là đúng?

Trả lời

9

Ví dụ có, tạm thời được xây dựng mặc định, và sau đó trình tạo bản sao được gọi để sao chép nó vào đối tượng của bạn t.

Tuy nhiên, trong thực tế các bản sao có thể được tối ưu hóa ra — mặc dù nó có tác dụng phụ (giao diện điều khiển đầu ra):

[n3290: 8.5/16]: [..] Trong một số trường hợp, một thực hiện là được phép được để loại bỏ việc sao chép vốn có trong việc khởi tạo trực tiếp này bằng cách xây dựng kết quả trung gian trực tiếp vào đối tượng đang được khởi tạo; xem 12.2, 12.8.

Và (kết hợp với các ví dụ được đưa ra trong mệnh đề giống nhau):

[n3290: 12.2/2]: [..] An thực hiện có thể sử dụng tạm thời trong để xây dựng X (2) trước khi đi qua nó tới f() bằng cách sử dụng công cụ xây dựng của X; cách khác, X(2) có thể được xây dựng trong không gian được sử dụng để giữ đối số. [..]

Nhưng hàm tạo bản sao hiện vẫn phải tồn tại, mặc dù nó có thể không được gọi.

Dù sao, nếu bạn biên dịch với optimisations tắt (hoặc, với GCC, có thể -fno-elide-constructors), bạn sẽ thấy:

This is ctor 
This is copy-ctor 
+2

Trong gcc, bạn có thể phải sử dụng '-fno-elide-constructors', vì ngay cả' -O0' cũng không ngăn chặn được sự cắt bỏ, tôi nghĩ vậy. –

+0

@Kerrek: Cảm ơn! –

+0

Bản sao có thể được elided ngay cả khi nó không phải là * tầm thường *, bản sao được elided bằng cách xây dựng tạm thời ở vị trí của biến địa phương. Độ phức tạp của đối tượng hoặc bản sao không liên quan đến tối ưu hóa đó. –

4

Về lý thuyết, X x = X() sẽ gọi constructor mặc định để tạo ra một đối tượng tạm thời, và sao chép vào x bằng cách sử dụng hàm tạo bản sao. Trong thực tế, các trình biên dịch được phép bỏ qua phần xây dựng bản sao và xây dựng mặc định x trực tiếp (như David chỉ ra trong bình luận của mình, vẫn yêu cầu hàm tạo bản sao có thể truy cập cú pháp). Hầu hết các trình biên dịch làm điều đó ít nhất là khi tối ưu hóa được kích hoạt.

+4

Điều quan trọng cần lưu ý là trình tạo bản sao phải có sẵn, ngay cả khi bản sao được chọn lọc. Đó là, nếu nó không thể truy cập trình biên dịch sẽ từ chối dòng với một lỗi. –

+0

@ David: Bạn nói đúng. Tôi đã kết hợp điều đó vào câu trả lời của mình. Cảm ơn đã đưa ra vấn đề này. – sbi

2

Đây là trường hợp hình thức Return Value Optimisation(RVO) (Còn được gọi là Copy Elision) có thể giúp ích rất nhiều cho việc tối ưu hóa. Các trang wikipedia liên kết có một lời giải thích rất tốt về những gì đang xảy ra.

+3

Tôi không nghĩ đó là chính xác. Không có hàm gọi ở đây trả về 'X' (nhớ rằng các hàm tạo không có giá trị trả về). Đây là bản sao chép, đó là một khái niệm liên quan, nhưng khác biệt. –

+0

Tôi đồng ý. Đây không phải là nghiêm ngặt RVO (mặc dù nó có liên quan). –

+0

@Tomak: Điều này cũng không hoàn toàn không chính xác. Đây là một biến thể của * loại tối ưu hóa đó. 1 để đối trọng với downvote. –

Các vấn đề liên quan