2017-08-26 19 views
8

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*, sizecapacity - 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?

+1

Quyền truy cập vào 'char' của mọi chữ ký luôn được cho phép. – o11c

+1

Một số mã tương tự trong Boost dẫn đến lỗi: https://svn.boost.org/trac10/ticket/12183 –

+0

@ 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''. –

Trả lời

11

Không chỉ có vẻ như là UB, nó là khá cần thiết, bởi vì việc sử dụng duy nhất của bytes_ dường như là để đọc các byte cuối cùng của this, có thể được thực hiện mà không UB:

reinterpret_cast<const char*>(this)[sizeof(*this) - 1] 

Đó là nhờ sự miễn trừ đặc biệt trong C++ cho phép tái diễn các đối tượng như mảng char.

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