jacobsa
jacobsa

Reputation: 6638

What would the downsides be of using [[no_unique_address]] all over the place?

[[no_unique_address]] allows structs to be more efficiently laid out, by sometimes putting members into tail padding of preceding members. We all like to save RAM and have more cache-efficient structs. So why not use it everywhere, all the time?

With reference to the C++ standard and/or the Itanium C++ ABI, what reasons are there to avoid using [[no_unique_address]] on most or all members?

For example:


I came to this question while pondering why libc++'s std::variant doesn't use [[no_unique_address]] for its state, meaning I can't use it in a struct that needs to be layed out efficiently into another and can do better with an open-coded union and tag. It's not clear to me whether [[no_unique_address]] could be safely used in std::variant assuming we don't care about an ABI change. But I'm interested in the wider question of what the downsides are in general.

Upvotes: 10

Views: 262

Answers (1)

Michael Mahn
Michael Mahn

Reputation: 797

There are definitely cases where the behavior of a well defined program can become unspecified by adding [[no_unique_address]]. A somewhat contrived example I could come up with:

#include <functional>
#include <iostream>

struct X {
    [[no_unique_address]] std::greater<> g;
    [[no_unique_address]] std::less<> l;
};

void
foo(auto const& comp1, auto const& comp2) {
    if(static_cast<void const*>(&comp1) == static_cast<void const*>(&comp2)) {
        std::cout << comp1(10, 5);
    } else {
        std::cout << comp1(10, 5) << comp2(5, 10);
    }
}

int main()
{
    X x;
    foo(x.l, x.g);
}

We're creating a struct with two different comparsion functors and passing them as parameters to a function. This function checks first if they're equal by comparing their address and if so only executes one, otherwise both.

With [[no_unique_address]] it's unspecified which branch this program will execute. But without, you can be guaranteed that it will execute the else branch.

So making [[no_unique_address]] the default might have broken some old code.

Upvotes: 5

Related Questions