Tôi có templated gray_code
lớp đó là có nghĩa là để lưu trữ một số nguyên unsigned có bit cơ bản được lưu trữ trong thứ tự mã màu xám. Ở đây là:Khởi tạo giá trị: khởi tạo mặc định hoặc khởi tạo không?
template<typename UnsignedInt>
struct gray_code
{
static_assert(std::is_unsigned<UnsignedInt>::value,
"gray code only supports built-in unsigned integers");
// Variable containing the gray code
UnsignedInt value;
// Default constructor
constexpr gray_code()
= default;
// Construction from UnsignedInt
constexpr explicit gray_code(UnsignedInt value):
value((value >> 1)^value)
{}
// Other methods...
};
Trong một số thuật toán chung, tôi đã viết một cái gì đó như thế này:
template<typename UnsignedInt>
void foo(/* ... */)
{
gray_code<UnsignedInt> bar{};
// Other stuff...
}
Trong đoạn mã này, tôi mong đợi bar
là zero-intialized và do đó bar.value
là zero- được khởi tạo. Tuy nhiên, sau khi đấu tranh với các lỗi không mong muốn, có vẻ như bar.value
được khởi tạo với rác (chính xác là 4606858) thay vì 0u
. Đó là làm tôi ngạc nhiên, vì vậy tôi đã đi đến cppreference.com để xem những gì các dòng trên được chính xác phải làm gì ...
Từ những gì tôi có thể đọc, hình thức T object{};
tương ứng với value initialization. Tôi thấy báo giá này thú vị:
Trong tất cả các trường hợp, nếu cặp dấu ngoặc nhọn {} được sử dụng và T là một loại tổng hợp, tổng hợp-khởi tạo được thực hiện thay vì khởi tạo giá trị.
Tuy nhiên, gray_code
có một hàm tạo do người dùng cung cấp. Do đó nó không phải là một tổng hợp do đó aggregate initialization không được thực hiện. gray_code
không có hàm tạo nào tham gia std::initializer_list
do đó list initialization cũng không được thực hiện. Các giá trị khởi tạo của gray_code
thì nên làm theo các thông thường C++ 14 quy tắc của giá trị khởi tạo:
1) Nếu T là một loại lớp không có constructor mặc định hoặc với một constructor mặc định người dùng cung cấp hoặc với một xóa constructor mặc định, đối tượng được khởi tạo mặc định.
2) Nếu T là loại lớp không có trình tạo mặc định do người dùng cung cấp hoặc bị xóa (có nghĩa là, nó có thể là một lớp với hàm tạo mặc định) hoặc đối tượng không được khởi tạo và sau đó nó được khởi tạo mặc định nếu nó có một hàm tạo mặc định không tầm thường.
3) Nếu T là một loại mảng, mỗi phần tử của mảng được khởi tạo giá trị.
4) Nếu không, đối tượng không được khởi tạo.
Nếu tôi đọc một cách chính xác, gray_code
có một constructor mặc định mặc định một cách rõ ràng (không dùng cung cấp), do đó 1) không áp dụng. Nó có một hàm tạo mặc định mặc định, vì vậy 2) áp dụng: gray_code
là zero-initialized. Mặc định constructor mặc định dường như đáp ứng tất cả các yêu cầu của một constructor mặc định tầm thường, do đó, khởi tạo mặc định không nên xảy ra. Chúng ta hãy có một cái nhìn đó như thế nào gray_code
là zero-khởi tạo:
Nếu T là một kiểu vô hướng, giá trị ban đầu của đối tượng là không liên tục không thể thiếu ngầm chuyển đổi sang T.
Nếu T là một loại lớp không phải công đoàn, tất cả các lớp cơ sở và thành viên dữ liệu không tĩnh đều được khởi tạo bằng 0 và tất cả các phần đệm được khởi tạo thành 0 bit. Các nhà thầu, nếu có, được bỏ qua.
Nếu T là kiểu kết hợp, thành viên dữ liệu không được đặt tên đầu tiên không được khởi tạo bằng 0 và tất cả các phần đệm được khởi tạo thành 0 bit.
Nếu T là kiểu mảng, mỗi phần tử là zero-khởi
Nếu T là kiểu tham chiếu, không có gì được thực hiện.
gray_code
là một loại lớp phi công đoàn. Vì vậy, tất cả các thành viên dữ liệu không tĩnh của nó nên được khởi tạo có nghĩa là value
không được khởi tạo. value
thỏa mãn std::is_unsigned
và do đó là một loại vô hướng, có nghĩa là nó phải được khởi tạo với "hằng số không đổi không được chuyển đổi hoàn toàn thành T". Vì vậy, nếu tôi đọc chính xác tất cả những điều đó, trong hàm foo
ở trên, bar.value
phải luôn được khởi tạo với 0
và nó không bao giờ nên được khởi tạo với rác, tôi có đúng không? Không phải lúc nào cũng được khởi tạo?
Lưu ý: trình biên dịch tôi biên dịch mã của tôi là MinGW_w4 GCC 4.9.1 với (chủ đề POSIX và ngoại lệ lùn) trong trường hợp giúp. Trong khi đôi khi tôi nhận được rác trên máy tính của tôi, tôi không bao giờ quản lý để có được bất cứ điều gì khác hơn không với các trình biên dịch trực tuyến.
Cập nhật: Dường là một GCC lỗi rằng lỗi là của tôi và không phải của trình biên dịch của tôi. Trên thực tế, khi viết câu hỏi này, tôi cho rằng vì lợi ích của sự đơn giản mà
class foo {
foo() = default;
};
và
class foo {
foo();
};
foo::foo() = default;
là tương đương. Họ không phải. Dưới đây là trích dẫn từ C++ 14 tiêu chuẩn, phần [dcl.fct.def.default]:
Một chức năng là dùng cung cấp nếu nó là do người dùng khai báo và không rõ ràng mặc định hoặc xóa trên tờ khai đầu tiên.
Nói cách khác, khi tôi có giá trị rác, constructor mặc định defaulted tôi đã thực sự dùng cung cấp vì nó đã không được rõ ràng efaulted trên tuyên bố đầu tiên của mình. Vì vậy, những gì đã xảy ra không phải là khởi tạo zero nhưng khởi tạo mặc định. Cảm ơn @Columbo lần nữa vì đã chỉ ra vấn đề thực sự.
[dcl.fct.def.default]/5 "một chức năng được người dùng cung cấp nếu nó được người dùng khai báo và ** không được mặc định rõ ràng ** hoặc bị xóa trên khai báo đầu tiên". Nhà xây dựng của bạn không phải do người dùng cung cấp. – user657267
Bạn có thể đã viết 'UnsignedInt value {0}' thay vì đọc các trang và trang ... Tôi biết bạn biết. ;-) – davidhigh
lưu ý ... khởi tạo giá trị STILL không hoạt động trên trình biên dịch của Microsoft dưới dạng VS2013 – Mgetz