Danijel
Danijel

Reputation: 8620

Simplest fix for "error: taking the address of a temporary object"?

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]

  1. Is there a compiler switch to make it tolerate such constructs?
  2. What's the smallest code change to make such code compile usingclang++? Maybe the following?

a)

    struct context* ctx;   
    struct context tmp = { 0 };
    ctx = &(tmp);

b)

    struct context* ctx;   
    {
        struct context tmp = { 0 };
        ctx = &(tmp);
    }

Note:

Upvotes: 3

Views: 3668

Answers (4)

KamilCuk
KamilCuk

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

rustyx
rustyx

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

HolyBlackCat
HolyBlackCat

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

Ihor Drachuk
Ihor Drachuk

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

Related Questions