Hãy xem xét ba struct
s sau đây :
class blub {
int i;
char c;
blub(const blub&) {}
};
class blob {
char s;
blob(const blob&) {}
};
struct bla {
blub b0;
blob b1;
};
Trên các nền tảng điển hình int
có 4 byte, kích thước, sự sắp xếp và tổng số đệm 1 như sau:
struct size alignment padding
-------- ------ ----------- ---------
blub 8 4 3
blob 1 1 0
bla 12 4 6
Không có sự chồng chéo giữa việc lưu trữ của các thành viên blub
và blob
mặc dù kích thước 1 blob
về nguyên tắc có thể "phù hợp" trong phần đệm của blub
.
C ++ 20 giới thiệu no_unique_address
thuộc tính, cho phép các thành viên trống liền kề chia sẻ cùng một địa chỉ. Nó cũng cho phép rõ ràng kịch bản được mô tả ở trên về việc sử dụng phần đệm của một thành viên để lưu trữ một thành viên khác. Từ cppreference (nhấn mạnh của tôi):
Chỉ ra rằng thành viên dữ liệu này không cần phải có một địa chỉ khác với tất cả các thành viên dữ liệu không tĩnh khác của lớp. Điều này có nghĩa là nếu thành viên có loại trống (ví dụ: Allocator không trạng thái), trình biên dịch có thể tối ưu hóa nó để chiếm không gian, giống như nếu nó là một cơ sở trống. Nếu thành viên không trống, bất kỳ phần đệm đuôi nào trong đó cũng có thể được sử dụng lại để lưu trữ các thành viên dữ liệu khác.
Thật vậy, nếu chúng ta sử dụng thuộc tính này blub b0
, kích thước của bla
giọt sẽ giảm 8
, do đó, blob
thực sự được lưu trữ trong blub
như đã thấy trên godbolt .
Cuối cùng, chúng tôi nhận được câu hỏi của tôi:
Văn bản nào trong các tiêu chuẩn (C ++ 11 đến C ++ 20) ngăn chặn sự chồng chéo này mà không có no_unique_address
, đối với các đối tượng không thể sao chép tầm thường?
Tôi cần loại trừ các đối tượng có thể sao chép (TC) tầm thường khỏi các đối tượng trên, bởi vì đối với các đối tượng TC, nó được phép chuyển std::memcpy
từ đối tượng này sang đối tượng khác, bao gồm các đối tượng con thành viên và nếu lưu trữ bị chồng chéo thì điều này sẽ phá vỡ (vì tất cả hoặc một phần của lưu trữ cho các thành viên liền kề sẽ được ghi đè) 2 .
1 Chúng tôi tính toán phần đệm đơn giản là sự khác biệt giữa kích thước cấu trúc và kích thước của tất cả các thành viên cấu thành của nó, theo cách đệ quy.
2 Đây là lý do tại sao tôi có các hàm tạo sao chép được xác định: để tạo blub
và blob
không thể sao chép một cách tầm thường .