2016-01-03 17 views
10

Tôi đang cố gắng hiểu cách các liên minh được mở rộng bằng C++ 11. Một điều đã thay đổi là khả năng sử dụng các thành viên dữ liệu không tĩnh với các chức năng thành viên đặc biệt không tầm thường. Từ cppreference.comCông đoàn trong C++ 11: hàm tạo mặc định dường như bị xóa

Nếu một liên minh có chứa một thành viên dữ liệu không tĩnh với một không tầm thường chức năng đặc biệt thành viên (constructor mặc định, sao chép/constructor di chuyển, sao chép/chuyển nhượng di chuyển, hoặc destructor), chức năng đó sẽ bị xóa theo mặc định trong công đoàn và cần được xác định rõ ràng bởi lập trình viên. Tối đa một thành viên dữ liệu có thể có trình khởi tạo thành viên mặc định.

tôi đang cố gắng đoạn mã sau:

struct X 
{ 
    ~X() {}; 
}; 

union U 
{ 
    X x; 
    ~U() {}; 
}; 

int main() 
{ 
    U s1{}; // works, probably aggregate initialization 
    U s2; // DOES NOT compile, why? 
} 

Live on Coliru

Đây X (được sử dụng như một thành viên dữ liệu của các công đoàn) đã một người dùng cung cấp destructor, vì thế mà destructor của công đoàn theo mặc định bị xóa. Do đó tôi cung cấp một cách rõ ràng. Tuy nhiên, mã thất bại trong việc biên dịch, với các lỗi

lưu ý: 'U :: U()' được mặc nhiên bị xóa vì định nghĩa mặc định sẽ là vô hình thành:

mã biên dịch nếu Tôi xóa dòng cuối cùng U s2;.

Câu hỏi Điều gì đang xảy ra ở đây? Tại sao biên dịch U s1{};, nhưng U s2; thì không? Là ctor mặc định của công đoàn được đánh dấu là đã xóa (nếu có, tại sao ?!), và trong trường hợp đầu tiên chúng ta chỉ cần khởi tạo tổng hợp? Lưu ý rằng nếu tôi cung cấp U(){}; // not U() = default; mã biên dịch (nhưng không phải nếu tôi chỉ cung cấp một ctor của X).

EDIT

Sau khi đào sâu vào các tiêu chuẩn (N4527):

đoàn: 9.5/2 [class.union]

[Ghi chú: Nếu bất kỳ không tĩnh thành viên dữ liệu của một công đoàn có một hàm tạo mặc định nhỏ (12.1), sao chép hàm (12.8), di chuyển hàm khởi tạo (12.8), toán tử gán (12.8), di chuyển toán tử gán (12.8), hoặc hàm hủy (12.4). thành viên func tion của công đoàn phải được người dùng cung cấp hoặc nó sẽ bị xóa hoàn toàn (8.4.3) cho công đoàn. —endnote]

có vẻ như đây là lỗi gcc (hiện được báo cáo here). Mã biên dịch trên clang và gcc 4.8.2 hoặc cũ hơn, nó phá vỡ trên gcc4.9 và sau đó (nhờ @ T.C. Để chỉ ra).

Trình biên dịch: g ++ 5.3, -std=c++11 được sử dụng.

+1

[Clang] (http://coliru.stacked-crooked.com/a/b58a360400009fa9) hoàn toàn hài lòng với mã này. Điều này trông giống như một lỗi GCC với tôi, thực sự. –

+0

@ T.C. Có, tôi thực sự đã thấy điều này ngay sau khi nhận xét của bạn. Lần đầu tiên tôi có tiếng kêu ấn tượng cũng đã từ chối nó, có thể đã được thử nghiệm một số phiên bản sửa đổi. Đã chỉnh sửa dòng cuối cùng của câu hỏi, cảm ơn. – vsoftco

+0

@ T.C. Tôi sẽ cố gắng đào sâu vào tiêu chuẩn ... – vsoftco

Trả lời

2

Trích dẫn cppreference không rõ ràng. Điều gì xảy ra là nếu ANY người nhận của liên minh xác định ANY của các chức năng thành viên đặc biệt không tầm thường này, thì TẤT CẢ trong số đó sẽ bị xóa theo mặc định trong liên minh.

Vì vậy, vì bạn có một destructor không tầm thường cho X, hàm tạo mặc định U sẽ bị xóa.

+0

Cảm ơn, nếu điều này là như vậy thì nó có ý nghĩa hoàn hảo. Và 'U s1 {};' hoạt động bởi vì chúng ta sử dụng khởi tạo tổng hợp, đúng không? – vsoftco

+0

Chủ yếu là, vâng. Các quy tắc C++ 11 cho phép bạn có các kiểu phức tạp hơn trong các công đoàn, nhưng bạn phải quản lý việc gọi các hàm tạo và các trình phá hủy của chúng theo cách thủ công dựa trên bất kỳ loại thẻ nào bạn sử dụng trong đối tượng/hàm quản lý liên kết. Thông thường, điều này có nghĩa là sử dụng vị trí mới/xóa. –

+0

Bạn có báo giá? Tôi không nghĩ đó là tiêu chuẩn nói. –

1

X không phải là loại nhóm vì không đồng bộ về mặt trivially vì nó có destructor Ngoài ra U không phải là loại nhóm.

U s2; cố gắng để gọi costructor mặc định đó sẽ bị xóa nên lỗi

U s1 {}; thành viên sử dụng khôn ngoan khởi và không gọi cho bất kỳ costructor

Trong hiệp nhất với thành viên phi pod các costructor mặc định của công đoàn bị xóa vì nó sẽ gọi hàm tạo mặc định của các thành viên, tức là trình biên dịch không biết thành viên nào gọi cho hàm lập trình mặc định

costructor mặc định của XX không thể gọi costructor mặc định của m1 AND m2 để nó bị xóa

+1

Đồng ý với tuyên bố của bạn, nhưng những gì tôi không hiểu là lý do tại sao constructor mặc định bị xóa. – vsoftco

+0

@ vsoftco Tôi thêm một số giải thích về những gì tôi nghĩ rằng nó appens – alangab

+0

Nó có thể là trường hợp, mặc dù tôi thấy không có lý do tại sao trình biên dịch không thể chỉ gọi constructor của thành viên đầu tiên. Giống như khi bạn thực hiện 'XX x {" test "};', trình biên dịch gọi hàm ctor của 'm1', tức là ctor của thành viên đầu tiên. – vsoftco

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