0

Here is a minimal program that segfaults with gcc-8.3.0, compiled with -std=c++2a:

struct Command {
    double x;
};

template <typename T>
struct AutoBrake {
    AutoBrake(const T& publish) : publish{ publish } {}
    const T& publish;
};

int main()
{
    int count{};
    AutoBrake brake{ [&count](const Command&) {
        count += 1;
    } };

    brake.publish(Command{ 1.1f });
}

Debugging shows that it crashes when accessing the count reference inside the lambda expression when running brake.publish.

However if the command struct does not contain any fields, the program runs fine:

struct Command {};
...

AFAIK since Command is taken as a const reference, its lifetime should be extended to the end of main here, so it should not be a dangling reference to a temporary.

Moreover if I do not access count in the lambda the program does not segfault:

...
    int count{};
    AutoBrake brake{ [&count](const Command&) {} };
    brake.publish(Command{});
...

Finally, if I first store the lambda as a variable it does not segfault:

    int count{};
    auto func = [&count](const Command&) { count += 1; };
    AutoBrake brake{ func };
    brake.publish(Command{});
abhijat
  • 535
  • 6
  • 12
  • 1
    [some const reference still doesn't prolong the lifetime of a temporary today](https://stackoverflow.com/questions/2784262/does-a-const-reference-class-member-prolong-the-life-of-a-temporary). – felix Jan 02 '20 at 09:01

1 Answers1

3

You store dangling lambda in AutoBrake.

You might do either:

template <typename T>
struct AutoBrake {
    AutoBrake(const T& publish) : publish{ publish } {}
    T publish;
};

or

int count{};
auto lambda = [&count](const Command&) {
        count += 1;
    };
AutoBrake brake{ lambda };

Your "working" variations are just possible outputs of Undefined Behaviour (UB).

Jarod42
  • 203,559
  • 14
  • 181
  • 302