2017-03-17 35 views
7

Tại cppref, tôi nhìn thấy một loại đặc điểm kiểm tra kỳ lạ: std::has_unique_object_representationsLoại nào sẽ khiến "std :: has_unique_object_representations" trả về false?

Từ mô tả của nó, tôi không thể tưởng tượng bất kỳ loại T mà làm std::has_unique_object_representations<T>::valuefalse.

Có bất kỳ ví dụ ngược lại nào không?

+0

Từ ngữ ở đây http://en.cppreference.com/w/cpp/types/has_unique_object_representations ngụ ý T cần phải được trivially có thể sao chép và cũng đưa ra một số lý do. –

+3

Các phao tương thích IEEE 754 là một ví dụ, vì các biểu diễn của các số 0 dương và âm khác nhau, nhưng các giá trị của chúng rõ ràng là bằng nhau. – Fanael

+2

Ngoài ra, bất kỳ loại nào có nhiều bit đệm tổng số không bằng 0. – Fanael

Trả lời

9

Hiểu được mục đích của đặc điểm này đòi hỏi phải hiểu sự khác biệt giữa biểu diễn giá trị "đối tượng" và "biểu diễn đối tượng" của đối tượng. Từ tiêu chuẩn:

Các đối tượng đại diện của một đối tượng kiểu T là dãy gồm N đối tượng unsigned char đưa lên bởi các đối tượng kiểu T, trong đó N bằng sizeof(T). Biểu diễn giá trị của đối tượng là tập hợp các bit giữ giá trị loại T. Đối với các kiểu có thể sao chép một cách trivially, biểu diễn giá trị là một tập hợp các bit trong biểu diễn đối tượng xác định một giá trị, là một phần tử rời rạc của một tập các giá trị được xác định.

Vì vậy, đại diện đối tượng là tổng dung lượng của một đối tượng. Nhưng hãy xem xét các đối tượng sau:

struct T 
{ 
    char c; 
    int i; 
}; 

Trên nhiều hệ thống, sizeof(T) sẽ là 8. Tại sao? Vì int phải được căn chỉnh 4 byte nên trình biên dịch chèn 3 byte đệm giữa ci. Vì ba byte đó là một phần của bộ nhớ của đối tượng (dựa trên sizeof(T)), chúng là một phần của biểu diễn đối tượng của đối tượng.

Nhưng ba byte đó là không phải một phần của biểu diễn giá trị của nó. Nếu bạn đã sửa đổi các byte đó, chúng sẽ không ảnh hưởng đến các giá trị của c hoặc i hoặc bất kỳ điều gì khác về chúng.

Nếu bạn đã viết quá tải operator== cho T, các thay đổi đối với các byte đó sẽ không ảnh hưởng đến kết quả của nó. Mà cũng có nghĩa là nếu bạn đã viết một tình trạng quá tải operator==, nó không thể được thực hiện như thế này:

bool operator==(const T &lhs, const T &rhs) 
{ 
    return std::memcmp(&lhs, &rhs, sizeof(T)) == 0; 
} 

Tại sao không? Vì hai số T s có thể có các giá trị khác nhau cho các byte đệm đó, nhưng vẫn có cùng giá trị là ci. Và do đó họ có cùng một giá trị đại diện và do đó nên được coi là tương đương.

has_unique_object_representations là đúng khi đại diện đối tượng của T và đại diện giá trị của nó chính xác chồng lên nhau (và khi T là có thể sao chép được). Vì vậy, khi nào bạn sẽ quan tâm đến điều này?

Bạn có thể viết hàm băm tổng quát hoạt động trên bất kỳ loại có thể sao chép được một cách trivially T bằng cách đọc biểu diễn giá trị của nó dưới dạng một mảng byte và băm chúng. Vâng, bạn có thể làm điều đó, nhưng chỉ khi loại không có byte đệm.Và đó là những gì has_unique_object_representations cho bạn biết: rằng tất cả các byte trong vấn đề đại diện đối tượng.

Ngoài ra, lưu ý rằng float loại, sẽ không nhất thiết phải có giá trị này là đúng, vì bình đẳng nhị phân và dấu phẩy động ngang không giống với IEEE-754. Vì vậy, các loại có chứa float s cũng sẽ không nhất thiết phải có điều này là đúng sự thật. Thật vậy, việc triển khai sử dụng các số nguyên đã được bổ sung của một người, hoặc các số nguyên đã ký với các biểu diễn bẫy, cũng sẽ không có điều này đúng đối với các loại đó.

+0

Tôi nghĩ bạn đang thiếu một 'sizeof (T)' trong lời gọi 'memcmp'. –

+0

Điều gì về các loại có hành vi giống như hành vi nhưng là loại người dùng? Tôi có nghĩa là trong lý thuyết tôi có thể có cấu trúc có một thành viên uint32 nhưng thực hiện tất cả các hoạt động trên nó như thể nó là thành viên nổi. Nói cách khác, nó sẽ là một cấu trúc Float {uint32 f}; với tất cả các hoạt động được ngụ ý để Float hoạt động như được xây dựng trong phao. Ngoài ra tôi tưởng tượng các lớp chuỗi sẽ không phù hợp với điều này ... – NoSenseEtAl

+1

@NoSenseEtAl: Vâng, đó là một điểm tốt, nhưng trong nhiều trường hợp, hạn chế TriviallyCopyable sẽ loại bỏ những người ra (như trường hợp chuỗi). Sau khi tất cả, mặc dù toán tử 'Float :: == 'sẽ không quan tâm đến một số bit nhất định, theo như ngôn ngữ có liên quan, chúng vẫn ở đó và chúng vẫn quan trọng. –

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