2017-05-24 12 views
16

xem xét mã này:Những thay đổi nào đối với C++ đã thực hiện công việc khởi tạo sao chép cho lớp với hàm tạo rõ ràng?

struct X{ 
    explicit X(){} 
    explicit X(const X&){} 
}; 

void foo(X a = X()){} 

int main(){} 

Sử dụng tiêu chuẩn C++ 14, cả GCC 7.1 và Clang 4,0 rejects mã, đó là những gì tôi mong đợi.

Tuy nhiên, sử dụng C++ 17 (-std=c++1z), they both accept mã. Quy tắc nào đã thay đổi?


Đối với cả hai trình biên dịch để thể hiện hành vi tương tự này, tôi nghi ngờ đây là lỗi. Nhưng theo như tôi có thể nói, bản nháp mới nhất vẫn cho biết, đối số mặc định sử dụng ngữ nghĩa của sao chép khởi tạo. Một lần nữa, chúng tôi biết rằng các nhà xây dựng explicit sẽ chỉ cho phép khởi tạo trực tiếp .

: dcl.fct.default/5; : class.conv.ctor/2

+1

"Sao chép khởi tạo" không có nghĩa là bản sao sẽ được thực hiện. Ví dụ, 'struct A {int x; } a = {0}; 'cũng sử dụng khởi tạo sao chép' a' từ '{0}', nhưng không có bản sao nào được tạo. –

+0

@ JohannesSchaub-litb. Cảm ơn, tôi hiểu. Ngoài ra, báo giá của bạn [* "tỷ lệ phần trăm được khởi tạo" * khái niệm] (https://stackoverflow.com/questions/38043319/how-does-guaranteed-copy-elision-through-simplified-value-categories-work?noredirect=1&lq = 1 # comment66236253_38043447) trong Nicol Bolas trả lời [ở đây] (https://stackoverflow.com/questions/38043319/how-does-guaranteed-copy-elision-through-simplified-value-categories-work?noredirect=1&lq=1), bao gồm cả câu trả lời của Nicol đã giúp tôi hiểu được sự thay đổi sâu rộng đối với 'prvalue' và hiện thực hóa tạm brouhaha. – WhiZTiM

Trả lời

8

Bởi vì hành vi của copy elision thay đổi từ C++ 17; trong trường hợp này, việc tối ưu hóa là bắt buộc.

Theo các trường hợp sau, các trình biên dịch được yêu cầu phải bỏ các copy- và nhà thầu move- của lớp đối tượng ngay cả khi sao chép/di chuyển constructor và destructor có thể quan sát được tác dụng phụ:

  • Trong khởi tạo, nếu biểu thức khởi tạo là giá trị và phiên bản cv-unqualified của loại nguồn là cùng lớp với lớp đích, biểu thức khởi tạo được sử dụng để khởi tạo đối tượng đích:

    T x = T(T(T())); // only one call to default constructor of T, to initialize x 
    

và cho copy initialization:

Ảnh hưởng của bản khởi tạo là:

  • Thứ nhất, nếu T là một loại lớp và khởi tạo là một prvalue Biểu mẫu có loại cv không đủ tiêu chuẩn là cùng một lớp với T, khái niệm initializer chính nó, đúng hơn là một tạm thời cụ thể hóa từ nó, được sử dụng để khởi tạo đối tượng đích: xem copy elision (vì C++ 17)

  • Nếu T là một loại lớp và cv-không đủ tiêu chuẩn phiên bản loại khác là T hoặc lớp học có nguồn gốc từ T, các nhà thầu không rõ ràng của T được kiểm tra và kết hợp tốt nhất được chọn theo độ phân giải quá tải. Hàm khởi tạo sau đó được gọi để khởi tạo đối tượng.

Điều đó có nghĩa cho X a = X(), a sẽ được mặc định được xây dựng trực tiếp, sao chép/di chuyển nhà xây dựng và tác dụng phụ của họ sẽ được omiited hoàn toàn. Việc lựa chọn các nhà thầu không rõ ràng để giải quyết quá tải sẽ không diễn ra, được yêu cầu trong C++ 14 (và trước đó). Đối với những trường hợp được bảo đảm này, các nhà xây dựng sao chép/di chuyển không tham gia, thì không quan trọng là chúng có phải là explicit hay không.

+2

Điều này dường như không giải quyết được vấn đề cơ bản ở đây: sao chép elision chỉ hợp pháp nếu phiên bản không elided sẽ là hợp pháp. Vì vậy, ví dụ, một lớp với một hàm tạo bản sao riêng không thể được khởi tạo bởi một biểu thức như 'T t = T (3);', bởi vì hàm tạo bản sao là không thể truy cập được. Sao chép elision không làm cho mã này hợp pháp. –

+2

@PeteBecker: [* Bảo đảm * bỏ sót] (https://stackoverflow.com/questions/38043319/how-does-guaranteed-copy-elision-work/38043447#38043447). Không có bản sao hoặc di chuyển xảy ra C++ 17. Vì vậy, các nhà xây dựng bản sao rõ ràng là không bao giờ thậm chí xem xét. Nếu 'T (3)' là hợp pháp từ vị trí của nó, thì sử dụng giá trị đó để khởi tạo bất kỳ đối tượng nào của kiểu 'T' là hợp pháp. Cho dù bằng cách khởi tạo sao chép hoặc khởi tạo trực tiếp. –

+2

@PeteBecker Chỉ dành cho những người không được bảo vệ bản sao, các nhà xây dựng sao chép/di chuyển phải có mặt và có thể truy cập được. [live] (https://wandbox.org/permlink/OUUiQ0rHdfO1lCrt) – songyuanyao

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