Reputation: 8620
struct context* ctx = &(struct context){ 0 };
I am trying to use clang++
C++ compiler to compile C code, possibly with minimal code changes.
For the above code I get error:
error: taking the address of a temporary object of type 'struct context' [-Waddress-of-temporary]
clang++
? Maybe the following?a)
struct context* ctx;
struct context tmp = { 0 };
ctx = &(tmp);
b)
struct context* ctx;
{
struct context tmp = { 0 };
ctx = &(tmp);
}
Note:
-std=c++2a
option is used when compilingclang++
seems to tolerate (support?) designated initializersUpvotes: 3
Views: 3668
Reputation: 142005
Is there a compiler switch to make it tolerate such constructs?`
-Wno-address-of-temporary
...
But that would be just wrong. Compiling such code in C++ will result in a dangling pointer pointing to a memory of an object whose lifetime ended. The lifetime of temporary ends on ;
in that code - after the assignment, the pointer is just invalid.
What's the smallest code change to make such code compile using clang++? Maybe the following?
The code b)
is error prone - it leaves a pointer pointing to an object whose lifetime has ended.
I guess the "smallest" could be:
// in C++
context a,*ctx=&a;
// in C
struct context a={0},*ctx=&a;
Och, the smallest change would be to move the compund literal to previous line.
struct context t = {0};
struct context* ctx = &t;
Upvotes: 5
Reputation: 85541
In C, (struct context){ 0 }
is compound literal syntax that creates an instance of context
with a duration of the enclosing scope (e.g. it exists for the duration of the function call or block in which it is created).
In C++ on the other hand, (struct context){ 0 }
creates a temporary, it exists for the duration of the full-expression, usually until the first ;
. Note that (struct context){ 0 }
is not technically C++ (GCC understands it as a compiler extension), context{}
would be a C++ alternative, though the semantics are the same.
So in C++ mode, struct context* ctx = &(struct context){ 0 };
would initialize ctx
to point to a non-existent object (a dangling pointer). That's what the compiler is complaining about.
The solution could be to give this initial context a name at global or function scope:
struct context init_ctx = { 0 };
Then elsewhere in the code just use it:
struct context* ctx = &init_ctx;
That would work the same in C and C++. It even makes the code more readable (IMHO).
Upvotes: 4
Reputation: 96941
Short answer:
(b) is wrong, as it leaves you with a dangling pointer.
(a) is correct, but it can be shortened:
struct context tmp = {0};
struct context *ctx = &tmp;
If you no longer need to compile this as C, you can remove the struct
keywords here.
For the above code I get
error: taking the address of a temporary object of type 'struct context' [-Waddress-of-temporary]
Is there a compiler switch to make it tolerate such constructs?
Most likely no. Compound literals are a C-only feature.
Both GCC and Clang with -pedantic-errors
refuse to compile this code not because you take the address of a temporary, but because it's a compound literal.
Without -pedantic-errors
they only complain about taking the address of a temporary, meaning they treat (struct context){0}
as context{0}
, not as a proper compound literal (which should create a block-scope variable, not a temporary).
Upvotes: 2
Reputation: 1293
Using pointers and references to temporary data leads to undefined behavior. Never do this.
You should prolong lifetime of your object and then create pointer/reference to it, but be sure it's used only in period of object's lifetime. Probably std::shared_ptr
can help you, it will keep object alive until you loose references to it. But you shouldn't keep raw pointers to object if you switch to std::shared_ptr
Also you can create static
object - it will be alive until the program end. It's mostly safe to use pointers/references to it, but also have some pitfalls.
Upvotes: 1