2015-01-28 17 views
13

Hãy xem xét đoạn mã sau:hành vi khác nhau của C++ 11 list-khởi

class A { 
private: 
    std::string s; 
public: 
    A() = delete; 
    A(const A&) = delete; 
    A(A&&) = delete; 
    A(const std::string &a) : s(a) {} 
}; 

Bây giờ, tôi muốn khởi tạo một mảng của A danh sách sử dụng khởi tạo. g ++ (4.9.1) có thể xây dựng thành công đoạn mã sau:

int main() { 
    A arr[2] = {{"a"}, {"b"}}; 
    return 0; 
} 

Tuy nhiên, nó không cho đoạn mã sau:

class Aggr { 
private: 
    A arr[2]; 
public: 
    Aggr() : arr{{"a"}, {"b"}} {} 
}; 

Các thông báo lỗi,

test.cc: In constructor ‘Aggr::Aggr()’: 
test.cc:22:28: error: use of deleted function ‘A::A(A&&)’ 
    Aggr() : arr{{"a"}, {"b"}} {} 
          ^   
test.cc:11:3: note: declared here 
    A(A&&) = delete; 
^

Điều đó nói rằng , một trình khởi tạo danh sách cố gắng gọi một hàm khởi tạo di chuyển để khởi tạo một mảng bên trong một lớp. Mã đó, tuy nhiên, đã được xây dựng thành công bởi clang v3.5 mà không có bất kỳ cảnh báo nào. Vì vậy, tôi muốn biết C++ 11 (hoặc phiên bản mới hơn) quy định các quy tắc nào liên quan đến việc khởi tạo danh sách. Cảm ơn trước.

+0

Tại sao nó là 'A &&'? – ZivS

+0

@ZivS tham chiếu rvalue – bolov

+3

có thể liên quan đến vấn đề của bạn: http://stackoverflow.com/questions/26685551/how-to-initialize-array-of-classes-with-deleted-copy-constructor-c11 – marcinj

Trả lời

2

Đọc đi lặp lại tiêu chuẩn, tôi nghĩ đây là lỗi.

Tiêu chuẩn nói gì?

8.5.1/2: Khi một tổng thể được khởi tạo bởi một danh sách initializer, theo quy định tại 8.5.4, các yếu tố của danh sách initializer được lấy như initializers cho các thành viên của tổng hợp, trong việc tăng số chỉ số hoặc thành viên. Mỗi thành viên được sao chép-khởi tạo từ điều khoản khởi tạo tương ứng tương ứng.

Người ta giải thích rằng:

8,5/14: (...) được gọi là bản sao-khởi. [Ghi chú: Sao chép-khởi tạo có thể gọi một động thái (12.8). —thêm ghi chú]

Nhưng tôi không tìm thấy bằng chứng nào trong 12.8 rằng trong trường hợp cụ thể của bạn, việc di chuyển sẽ được yêu cầu.

8.5.4/3 Nếu không, nếu T là loại lớp, thì người xây dựng sẽ được xem xét. Nếu T có một hàm tạo danh sách khởi tạo, đối số liệt kê bao gồm danh sách khởi tạo làm đối số duy nhất; nếu không, danh sách đối số bao gồm các phần tử của danh sách bộ khởi tạo. Các nhà thầu có thể á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).

Vì vậy, về nguyên tắc, mã của bạn sẽ hoạt động!

Đây có phải là lỗi không? Đang thử cách thử nghiệm

Tôi đã nhận xét việc xóa hàm tạo di chuyển, để hưởng lợi từ hàm tạo di chuyển ẩn.Kỳ lạ thay, sau đó tôi nhận được thông báo lỗi sau:

Compilation error time: 0 memory: 3232 signal:0 

prog.cpp: In constructor 'Aggr::Aggr()': 
prog.cpp:19:28: error: use of deleted function 'A::A(const A&)' 
    Aggr() : arr{{"a"}, {"b"}} {} 
          ^
prog.cpp:10:3: note: declared here 
    A(const A&) = delete 

Vì vậy, bây giờ anh ấy phàn nàn về một nhà xây dựng bản sao còn thiếu!

Thậm chí còn kỳ lạ hơn, sau đó tôi đã cung cấp hàm tạo di chuyển của riêng mình thay vì hàm tạo ngầm: ở đây nó đã biên dịch mã thành công !!

Cuối cùng tôi cung cấp cả một bản sao và một động thái và thêm một số tracing:

class A { 
private: 
    std::string s; 
public: 
    A() = delete; 
    A(const A&) { std::cout<<"copy\n";} //= delete; 
    A(A&&) { std::cout<<"move\n";} //= delete; 
    A(const std::string &a) : s(a) { std::cout<<"string ctor\n";} 
}; 

Và khi tôi tạo một đối tượng Aggr, nó chỉ hiển thị:

string ctor 
string ctor 

cho thấy các thành viên mảng là khởi tạo form constructor chuỗi bằng cách sử dụng copy elision như chúng ta mong đợi.

Tất cả các thử nghiệm này được thực hiện với gcc-9.4.2 trên ideone với tùy chọn C++ 14.

Kết luận

Thực tế là cùng mã thất bại trong việc biên dịch với ctor thái tiềm ẩn và thành công với một người dùng xác định di chuyển ctor trông rất nghiêm túc như một lỗi.

Thực tế là hàm tạo di chuyển không được sử dụng khi nó có sẵn củng cố hiển thị này.

Do đó, tôi đã báo cáo this bug.

+0

Câu trả lời hay và cảm ơn bạn đã báo cáo lỗi này. – Destructor

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