Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What type will make "std::has_unique_object_representations" return false?

At cppref, I see a weird type trait checker: std::has_unique_object_representations

From its description, I cannot imagine any type T that make std::has_unique_object_representations<T>::value is false.

Is there any counter-example?

like image 805
xmllmx Avatar asked Mar 17 '17 10:03

xmllmx


1 Answers

Understanding the purpose of this trait requires understanding the distinction between an objects "value representation" and its "object representation". From the standard:

The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T). The value representation of an object is the set of bits that hold the value of type T . For trivially copyable types, the value representation is a set of bits in the object representation that determines a value, which is one discrete element of an implementation-defined set of values.

So, object representation is the total storage of an object. But consider the following object:

struct T
{
  char c;
  int i;
};

On many systems, sizeof(T) will be 8. Why? Because int has to be 4-byte aligned, so the compiler inserts 3 bytes of padding between c and i. Since those three bytes are part of the object's storage (based on sizeof(T)), they are part of the object's object representation.

But those three bytes are not part of its value representation. If you modified those bytes, they would not affect the values of c or i, or anything else about them.

If you wrote an operator== overload for T, changes to those bytes would not affect its results. Which also means that if you did write an operator== overload, it could not be implemented like this:

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

Why not? Because two Ts can have different values for those padding bytes, but still have the same value of c and i. And thus they have the same value representation and thus should be considered equivalent.

has_unique_object_representations is true when T's object representation and its value representation exactly overlay one another (and when T is trivially copyable). So, when would you care about this?

You can write a generalized hashing function that works on any trivially copyable type T by reading its value representation as an array of bytes and hashing them. Well, you could do that, but only if the type doesn't have padding bytes. And that's what has_unique_object_representations tells you: that all of the bytes in the object representation matter.

Also, note that float types, won't necessarily have this value be true, since binary equality and floating-point equality aren't the same thing in IEEE-754. So types which contain floats will also not necessarily have this be true. Indeed, implementations that use one's-complement signed integers, or signed integers with trap representations, will also not have this be true for such types.

like image 128
Nicol Bolas Avatar answered Oct 03 '22 10:10

Nicol Bolas