Hacker News new | past | comments | ask | show | jobs | submit login

A better example of address uniqueness being a problem is with code like:

    struct Marker {};
    struct Foo {
        Marker marker;
        int64_t number;
    };
If you write the equivalent in C with GCC extensions, or Rust, sizeof(Foo) would be 8, the same as sizeof(int64_t); `marker` doesn't take up any extra space. In C++, however, sizeof(Foo) is 16, because `marker` must take up at least 1 byte to have a unique address, which gets expanded to 8 bytes due to alignment.

Now, as of C++20, you can reduce sizeof(Foo) to 8 by tagging `marker` as [[no_unique_address]]. However, this has drawbacks. First of all, it's easy to get situations like this in highly generic code, so it's hard to predict where [[no_unique_address]] needs to be applied (and applying it everywhere would be verbose).

Second of all, [[no_unique_address]] is dangerous, because it doesn't just allow empty fields to be omitted, it also allows nonempty fields to have trailing padding bytes reused for other fields. Normally that's okay, but if you have any code that performs memcpy or memset or similar based on the size of a type, such as:

    struct Foo {
        Foo(const Foo &other) {
            memcpy(this, &other, sizeof(Foo));
        }
        // …some fields here…
    };
…then if that code writes to a [[no_unique_address]] field, it can overwrite adjacent fields, since sizeof(Foo) includes any trailing padding bytes!



I don’t really get the concern here. [[no_unique_address]] seems to be designed for use with empty types. As such, what does it mean to write to such a field? These are really meant to be tags, no?


it could come from a template function which don't have a sfinae branch (or `if constexpr (std::is_empty<T>::value)`) for empty type




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: