Reputation: 808
I want to use a stateless scope guard
struct ScopeGuard {
ScopeGuard();
~ScopeGuard();
};
void f();
int test() {
ScopeGuard scopeguard1;
ScopeGuard scopeguard2;
// doesn't work:
// [[no_unique_address]] ScopeGuard scopeguard3;
f();
}
The scope guard itself has no state, I am only interested in the side effects of the constructor/destructor.
I want test
to have a stack size of 0.
But scopeguard1
and scopeguard2
take 8 bytes of stack space each. This is because the this
pointer needs to be unique for each instance of ScopeGuard
, even if it is stateless.
Usually, I would want to use [[no_unique_address]]
in this situation. But it seems [[no_unique_address]]
only works for member variables but not for local variables inside functions.
Is there some other way to achieve this?
Why is [[no_unique_address]]
only supported for member variables? Was this an oversight in C++20? Was it intentional? Would there be any issues with allowing this attribute also for local variables?
Upvotes: 0
Views: 110
Reputation: 474436
I want
test
to have a stack size of 0. Butscopeguard1
andscopeguard2
take 8 bytes of stack space each. This is because thethis
pointer needs to be unique for each instance ofScopeGuard
, even if it is stateless.
How do you know that they don't?
If the compiler can see that nothing in ScopeGuard
actually cares about the value of the this
pointer, and nobody actually tries to take the address of a stack variable of this type, then the compiler is 100% free to not give such a variable space on the stack.
Also, you've misunderstood part of the behavior of no_unique_address
. Despite the name, it actually doesn't allow two instances of the same type to have the same address. It allows two instances of different types to overlap in member layouts. So even if you could declare those local variables with that attribute, the compiler could not given them the same address (assuming someone looked at the address at all).
no_unique_address
was needed for member variables because C++ has specific rules for how a type is laid out, and each member needs its own region of storage distinct from all others. no_unique_address
allowed members to break that rule, so long as the unique identity rule is satisfied.
For local variables, the compiler has the option to optimize the stack as it sees fit, so it doesn't need no_unique_address
to give it permission.
And don't forget: no_unique_address
doesn't provide any guarantees of anything either. It gives the compiler the option to optimize something away; it's never mandatory.
Upvotes: 4