9

Trước C++ 11, chúng ta có thể thực hiện khởi tạo sao chép bằng cách viết một cái gì đó như A a = 1; tương đương hoặc ít hơn tương đương với A a = A(1);. Tức là, một tạm thời được tạo ra đầu tiên và sau đó một ctor sao chép được gọi ra. Bất kể việc sao chép bản sao, điều này phải rất khái niệm và ctor sao chép phải có thể truy cập được.Sao chép danh sách sao chép có gọi ra bản sao ctor không?

Với khởi tạo danh sách trong C++ 11, chúng tôi có thể thực hiện khởi tạo danh sách sao chép bằng cách viết A a = {1, 2};. Theo ý kiến ​​của tôi, điều này ít nhiều sẽ tương đương với A a = A(1, 2);. Tuy nhiên, trên GCC và clang, A a = {1, 2} biên dịch ngay cả khi không thể truy cập được bản sao và di chuyển ctor (bằng cách khai báo là riêng tư). Tuy nhiên, A a = 1; không biên dịch trên GCC hoặc clang nếu không thể truy cập được ctor sao chép/di chuyển tương ứng. Vì vậy, A a = {1, 2}; có vẻ nhiều hơn hoặc ít hơn tương đương với A a{1, 2}; là khởi tạo danh sách trực tiếp. Sự khác biệt giữa điều này và khởi tạo danh sách trực tiếp thực sự là A a = {1, 2}; không biên dịch nếu ctor có hai int là rõ ràng. Trong khía cạnh này, A a = {1, 2}; giống với khởi tạo sao chép.

Vì vậy, câu hỏi của tôi là: ngữ nghĩa chính xác của các biểu thức như A a = {1, 2}; là khái niệm gì? Bằng cách khái niệm, sao chép elision không ở lại trong cách.

+2

Bạn đã tự giải thích mọi thứ trong câu hỏi. Sao chép danh sách khởi tạo giống như khởi tạo danh sách trực tiếp trừ trường hợp trước đây không xem xét các hàm tạo rõ ràng. Không yêu cầu hàm tạo bản sao có thể truy cập. – Praetorian

+0

@Praetorian Điều này có vẻ không chính xác như thế này. Xem bình luận của tôi cho câu trả lời của Columbo. – Lingxi

Trả lời

9

Tiêu chuẩn mô tả nó khá tốt; [Dcl.init.list]/3:

List-khởi của một đối tượng hoặc tài liệu tham khảo của loại T được định nghĩa như sau:

  • [...]
  • Ngược lại, nếu T là một kiểu lớp, các hàm tạo được xem xét. Các nhà thầu được áp dụng được liệt kê và được chọn là tốt nhất thông qua độ phân giải quá tải (13.3, 13.3.1.7). Nếu cần thu hẹp chuyển đổi (xem bên dưới) để chuyển đổi bất kỳ đối số nào, chương trình bị lỗi.

[over.match.list] (tôi nhấn mạnh):

Khi đối tượng của phi tổng hợp lớp loại T là danh sách khởi tạo (8.5.4), độ phân giải quá tải chọn nhà xây dựng trong hai giai đoạn:

  • Ban đầu, các chức năng ứng cử viên là các nhà thầu initializer-list (8.5.4) của lớp T và danh sách đối số con sists của danh sách khởi tạo như một đối số duy nhất.

  • Nếu không có constructor khởi tạo danh sách khả thi được tìm thấy, độ phân giải quá tải được thực hiện một lần nữa, nơi mà các chức năng ứng cử viên đều các nhà thầu của lớp T và danh sách đối số bao gồm các yếu tố của danh sách initializer.

Nếu danh sách khởi tạo không có yếu tố và T có một constructor mặc định, giai đoạn đầu tiên được bỏ qua.
Trong bản sao-danh sách khởi tạo, nếu một nhà xây dựng explicit được chọn, việc khởi tạo không đúng định dạng.

Do đó, nếu không tìm thấy hàm khởi tạo danh sách khởi tạo (như trong trường hợp của bạn), các phần tử của danh sách khởi tạo cấu thành các đối số cho lệnh gọi hàm tạo.
Trên thực tế, chỉ có khác biệt về khởi tạo danh sách trực tiếp và bắt đầu sao chép danh sách được bao gồm bởi câu in đậm cuối cùng.

Đây là một trong những ưu điểm của việc khởi tạo danh sách: Nó không đòi hỏi sự hiện diện của một hàm thành viên đặc biệt không được sử dụng.

+0

Sau đó, làm thế nào để giải thích sao chép danh sách-khởi tạo trong bối cảnh gọi hàm theo giá trị, ví dụ: 'f ({1, 2});'. Trên GCC và clang, điều này yêu cầu ctor sao chép/di chuyển có thể truy cập được. Nếu không, chương trình này không biên dịch. – Lingxi

+3

@Lingxi [** Thật vậy? **] (http://coliru.stacked-crooked.com/a/d85bfae98f38bea3) – Columbo

+0

Tôi đã thử nghiệm nó trên trình biên dịch trực tuyến nhúng của cppreference.com. Ví dụ: bạn có thể tìm thấy nó ở cuối http://en.cppreference.com/w/cpp/language/explicit – Lingxi

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