Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Where's the dangling reference, according to gcc 13?

39 views
Skip to first unread message

Sam

unread,
Apr 16, 2023, 7:05:25 PM4/16/23
to
I am in receipt of the following complaint from gcc 13 with -Wall -Werror:

t.C: In function ‘int gimme(const std::optional<int>&)’:
t.C:21:15: error: possibly dangling reference to a temporary [-Werror=dangling-reference]
21 | const auto &v=optional_arg_or<int>(value, def, 0);
| ^
t.C:21:37: note: the temporary was destroyed at the end of the full expression ‘optional_arg_or<int, int>((* & value), def, 0)’
21 | const auto &v=optional_arg_or<int>(value, def, 0);
| ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~

And here's the source. Can someone tell me where the dangling reference is:

#include <optional>
#include <utility>

template<typename ret_type, typename ...Args>
const ret_type &optional_arg_or(const std::optional<ret_type> &v,
std::optional<ret_type> &def,
Args && ...args)
{
if (v)
return *v;

def.emplace(std::forward<Args>(args)...);

return *def;
}

int gimme(const std::optional<int> &value)
{
std::optional<int> def;

const auto &v=optional_arg_or<int>(value, def, 0);

return v;
}

David Brown

unread,
Apr 17, 2023, 3:40:50 AM4/17/23
to
In "optional_arg_or", you are creating a temporary object of type
"ret_type" and returning a reference to it. That's the dangling reference.

I believe you are assuming that the optional<ret_type> object is a
struct containing a separate "ret_type" object, and it is valid to
return a reference to that subobject. But I don't think such an
assumption is valid.

I would suggest removing the references in "optional_arg_or" and
treating these all as values - let compiler optimisation handle the
generation of efficient code (copy elision and return value
optimisations probably guarantee efficient code). Dealing with values
rather than references is often more efficient anyway for small types
such as "int".


Sam

unread,
Apr 17, 2023, 7:06:05 AM4/17/23
to
I'm fairly certain that this is exactly what std::optional is.

https://en.cppreference.com/w/cpp/utility/optional/operator*

"Returns a reference to the contained value."

https://en.cppreference.com/w/cpp/utility/optional

"If an optional<T> contains a value, the value is guaranteed to be allocated
as part of the optional object footprint, i.e. no dynamic memory allocation
ever takes place. Thus, an optional object models an object, not a pointer,
even though operator*() and operator→() are defined."


David Brown

unread,
Apr 17, 2023, 9:18:40 AM4/17/23
to
OK. I am still not convinced it is safe to assume such pointers are
valid. (Maybe someone else will give you a better answer here.)

Anyway, return of the "optional_arg_or" call is a temporary, and you're
taking a reference to it. Change the line to "const auto v = ..." and
you should be okay.

When I am in doubt about this kind of thing, I make a little class with
an external constructor and destructor and look at what is called where.
It's easy to be mislead by the behaviour on simple types like "int".


Sam

unread,
Apr 17, 2023, 7:11:29 PM4/17/23
to
> When I am in doubt about this kind of thing, I make a little class with an

Actually I have no doubts, I'm fairly certain that this a second gcc bug
involving a spurious warning that I found. The first one was recently fixed,
sort of. The spurious warning was triggered in std::vector's bowels, in
certain situations. As far as I can decipher the bug updates they fixed it
by tweaking std::vector's code to avoid triggering the spurious warning; but
the warning was bogus.


> external constructor and destructor and look at what is called where. It's
> easy to be mislead by the behaviour on simple types like "int".

That sounds like a reasonable suggestion, so:

#include <iostream>

struct my_optional {

int value{0};

my_optional()
{
std::cout << "constructor" << std::endl;
}

~my_optional()
{
std::cout << "destructor" << std::endl;
}

const int &operator*() const
{
return value;
}
};

const int &get_my_optional(const my_optional &o)
{
return *o;
}

int main()
{
my_optional opt;

const int &value= *opt;

std::cout << "value: " << value << std::endl;
return 0;
}

Result:

constructor
value: 0
destructor

UPDATE: I'm now fairly sure that this has nothing to do with any cockamamie
temporary returned from any cockamamie function. The following also trips
this warning. Replacing the "int &&def_val" parameter with "int defval"
fixes this warning:

#include <optional>
#include <utility>

const int &optional_arg_or(std::optional<int> &def,
int &&def_val)
{
def = def_val;

return *def;
}


int gimme()
{
std::optional<int> def;

const int &v=optional_arg_or(def, 0);

int bologna=v;

return bologna;
}

int salami()
{
std::optional<int> def;

def = 0;

return *def;
}


gimme() and salami() do the same thing, but gimme() barks, and changing the
parameter to "int def_val" shuts it up. Definitely a gcc bug.

David Brown

unread,
Apr 18, 2023, 3:12:58 AM4/18/23
to
Fair enough - I've said what I think, but I am not at all sure I was
accurate. I suggest you file a bug in gcc, and/or make a post in the
gcc help or development mailing lists, and see what the gcc folks say
about it. They know more about the fine details of C++ than the great
majority of people - more than most of the experts in this newsgroup,
and certainly far more than me. And of course they understand gcc
better. Compiler warnings are not always an exact science - occasional
false positives and false negatives are unavoidable, but reporting
suspected errors back to the developers is always useful.

Sam

unread,
Apr 18, 2023, 6:59:02 AM4/18/23
to
Which is what I did yesterday, and it turned out that I wasn't the only one
to encounter this. This warning is bogus. The capsule summary is that all
that gcc was doing is checking if a function parameter is a reference, and
the function returns the same type, a reference, and if the actual function
parameter in a call is a temporary. It's not even looking at what the
function is doing. Under these circumstances this warning is issued. That's
supposed to be its purpose.

I'm all for static analysis, but this one tips the scales in the other
direction, this warning creates too much useless noise, and false positives.
On a case by case basis, if I don't feel like tweaking the code to avoid it
I'll just turn off this warning, entirely.


0 new messages