Lớp fbstring_core của Facebook sử dụng "Tối ưu hóa chuỗi nhỏ" được mô tả trong this talk trong đó lưu trữ cho các thành viên dữ liệu của lớp - Char*
, size
và capacity
- sẽ được lưu lại để lưu trữ dữ liệu ký tự nếu chuỗi đủ nhỏ. Các bit cờ được sử dụng để phân biệt giữa các trường hợp này được đặt trong "char bên phải của bộ nhớ". Câu hỏi của tôi là liệu việc truy cập các bit này thông qua thành viên công đoàn bytes_
, không bao giờ thực sự được viết, cấu thành hành vi không xác định theo tiêu chuẩn C++ 11? Câu trả lời cho số Accessing inactive union member and undefined behavior? cho biết.Tối ưu hóa chuỗi nhỏ của FBString có dựa vào hành vi không xác định không?
Đoạn trích sau chứa khai báo của các thành viên này và hàm thành viên category()
được sử dụng để xác định xem tối ưu hóa này có hiệu lực hay không.
typedef uint8_t category_type;
enum class Category : category_type {
isSmall = 0,
isMedium = kIsLittleEndian ? 0x80 : 0x2,
isLarge = kIsLittleEndian ? 0x40 : 0x1,
};
Category category() const {
// works for both big-endian and little-endian
return static_cast<Category>(bytes_[lastChar] & categoryExtractMask);
}
struct MediumLarge {
Char * data_;
size_t size_;
size_t capacity_;
size_t capacity() const {
return kIsLittleEndian
? capacity_ & capacityExtractMask
: capacity_ >> 2;
}
void setCapacity(size_t cap, Category cat) {
capacity_ = kIsLittleEndian
? cap | (static_cast<size_t>(cat) << kCategoryShift)
: (cap << 2) | static_cast<size_t>(cat);
}
};
union {
uint8_t bytes_[sizeof(MediumLarge)]; // For accessing the last byte.
Char small_[sizeof(MediumLarge)/sizeof(Char)];
MediumLarge ml_;
};
Dường như thực hiện điều này phụ thuộc vào việc sử dụng "loại punning" để truy cập vào một byte có thể thực sự là một phần của size_t capacity_
thành viên. Từ câu trả lời cho câu hỏi được liên kết ở trên, tôi thu thập rằng này là hành vi được xác định trong C99, nhưng không phải là trong C++ 11?
Quyền truy cập vào 'char' của mọi chữ ký luôn được cho phép. – o11c
Một số mã tương tự trong Boost dẫn đến lỗi: https://svn.boost.org/trac10/ticket/12183 –
@ o11c: '' uint8_t'' được định nghĩa là bí danh cho kiểu '' char'' , Tuy nhiên? Có vẻ như an toàn hơn khi sử dụng '' unsigned char''. –