11

Tại saoTại sao "ctor() = mặc định" hành vi thay đổi khi các nhà thầu khác có mặt?

struct wrapper 
{ 
    explicit wrapper(void *); 
    wrapper() = default; 
    int v; 
}; 

int main() { return wrapper().v; } // You should run this in Debug mode 

trở 0xCCCCCCCC, trong khi

struct wrapper { wrapper() = default; int v; }; 
int main() { return wrapper().v; } 

struct wrapper { int v; }; 
int main() { return wrapper().v; } 

cả trở 0?

+1

khi bạn thêm hàm tạo non-= mặc định, loại không còn là tổng hợp. Tôi chắc chắn rằng đó là chơi vào điều này, không chắc chắn như thế nào mặc dù. Tôi nghi ngờ bạn chắc chắn rằng nó là 0 trong cả hai trường hợp. –

+0

@RyanHaining: Bạn có chắc chắn không? Nếu vậy thì nó có vẻ kỳ lạ vì nó có nghĩa là thời gian duy nhất bạn có thể sử dụng '= mặc định' sẽ là khi không có các nhà xây dựng khác hiện diện, có vẻ vô nghĩa ... – Mehrdad

+0

' = default' sẽ trả về hàm tạo mặc định nhưng 'v' không được định nghĩa trong cả hai trường hợp. Với gcc tôi nhận được 0 ngay cả trong trường hợp đầu tiên, nhưng tất cả chỉ là tình cờ. –

Trả lời

4

Trong giá trị khởi tạo, nếu T là một loại lớp mà không có một người dùng cung cấp hoặc xóa mặc định-nhà xây dựng, sau đó đối tượng là zero-khởi (§8.5/8.2). Đây thực sự là trường hợp với wrapper.

ví dụ đầu tiên của bạn phù hợp với trường hợp thứ ba cho zero-khởi (§8.5/6.1, tôi nhấn mạnh)

- nếu T là một loại vô hướng (3.9), các đối tượng được khởi tạo với giá trị thu được bằng cách chuyển đổi số nguyên 0 (số không) thành T;

- nếu T là loại nhóm không phải là công đoàn, mỗi thành viên dữ liệu không tĩnh và mỗi đối tượng phụ lớp cơ sở không được khởi tạo và đệm được khởi tạo thành 0 bit;

- nếu T là loại liên kết (có thể cv đủ điều kiện), thành viên dữ liệu không được đặt tên đầu tiên của đối tượng là không được khởi tạo và đệm được khởi tạo thành 0 bit;

- nếu T là một kiểu mảng, mỗi phần tử là zero-khởi

- nếu T là một loại tài liệu tham khảo, không khởi tạo được thực hiện

Vì vậy, trong ví dụ đầu tiên của bạn, v nên không được khởi tạo. Điều này trông giống như một lỗi.

Trong ví dụ thứ hai và thứ ba, bạn không còn có một hàm tạo do người dùng cung cấp, nhưng bạn có một hàm tạo mặc định không được người dùng cung cấp hoặc xóa để ví dụ của bạn vẫn rơi vào trường hợp thứ ba , nghĩa là không khởi tạo từng thành viên dữ liệu không tĩnh. VS là chính xác ở đó.

+0

Đã có lỗi trong tiêu chuẩn C++ 11.Nếu bạn đọc IS, nó nói "mà không có một nhà xây dựng người dùng cung cấp", mà thiếu "mặc định" rất quan trọng. – dyp

+0

@dyp: "IS" là gì? – Mehrdad

+6

@Mehrdad: D oh, điều đó đã trở nên mơ hồ gần đây - Tôi đang đề cập đến Tiêu chuẩn quốc tế. Xem thêm: http://open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1301 – dyp

4

Điều này có vẻ như là một lỗi trong MSVC. Trong cả ba trường hợp wrapper không có người dùng cung cấp constructor mặc định, vì vậy khởi với wrapper() gọi:

(Tất cả các trích dẫn từ n3690)

(8,5/11) Một đối tượng có initializer là một tập rỗng ngoặc , tức là,(), sẽ được khởi tạo giá trị.

(nhờ dyp), điều này sẽ dẫn đến zero-intialization của int v

Khởi sau đó dùng chúng ta đến quy tắc:

(8,5/8) nếu T là một (có thể cv-đủ điều kiện) loại lớp mà không có một constructor mặc định do người dùng cung cấp hoặc bị xóa, sau đó đối tượng là zero-initialized và các ràng buộc ngữ nghĩa để khởi tạo mặc định được chọn.

Các zero khởi nguyên tắc nhà nước:

(8,5/6) nếu T là một (có thể cv-đủ điều kiện) phi đoàn kiểu lớp, mỗi thành viên dữ liệu không tĩnh và mỗi cơ sở hạng subobject là zero-khởi và đệm được khởi tạo bằng không bit

int v trở thành một thành viên dữ liệu wrapper là zero initialiazed tự theo:

(8,5/6) nếu T là một kiểu vô hướng (3.9), các đối tượng được khởi tạo với giá trị thu được bằng cách chuyển đổi các số nguyên literal 0 (zero) để T

Mà không phải là hành vi mà bạn quan sát .

+0

Nó sẽ được tốt đẹp nếu bạn có thể giải thích lý do tại sao GCC và Clang đang trải qua những rắc rối thêm để khởi tạo giá trị tất cả mọi thứ nếu bạn nghĩ rằng VC++ là chính xác trong không làm như vậy. – Mehrdad

+0

@Mehrdad Tôi đã đảo ngược mọi thứ –

+0

@dyp đây là điểm C++ nhỏ nhất mà tôi từng bị (bị đẩy tới) nhấn. –

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