-1

I am trying to use the value from a std::bitset inside of a lambda function but I am experiencing unexpected behavior:

int main()
{
    auto lambda = [](unsigned int param)
    {   
        std::bitset<10> bits(param);
        std::cout << "inside lambda bits[8] = " << bits[8] << std::endl; 
        return bits[8];
    };

    // 0x11c is 1_0001_1100 in binary
    auto result = lambda(0x11c);
    std::cout << "result = " << result << std::endl;
}

I would expect the value of result to be one since result is of type bool which can be copied from the local stack but instead the output is the following:

inside lambda bits[8] = 1
result = 0

What am I overlooking here?

markf78
  • 597
  • 2
  • 7
  • 25
  • 1
    I do not use `std::bitset` very often, but this question intrigued me. Seemed quite weird. I figured it out in about ten seconds. How? I simply compiled and ran the shown code in a debugger, and inspected what all the variables are, and what all expressions are really returning, and then the reason for this was very apparent. This is what you should do: learn how to use a debugger to solve puzzles like this. Knowing how to effectively use a debugger is a mandatory skill for every C++ developer. It's ok if you are not yet skilled at debugging, everyone has to start somewhere, how about now? – Sam Varshavchik Sep 13 '20 at 15:00
  • 1
    *since result is of type bool* -- How did you verify this? How do you know what's behind those `auto` keywords? – PaulMcKenzie Sep 13 '20 at 15:06
  • 1
    [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/q/25385173/5910058) – Jesper Juhl Sep 13 '20 at 15:15

1 Answers1

4

The operator[] for std::bitset returns a std::bitset::reference when called on a non-const std::bitset. This means the lambda (which deduces the return type), returns a reference to a local variable. This obviously dangles, and invokes undefined behavior when used at the call site.

You can fix this in several ways:

  1. Explicitly specify the return type of the lambda, so the reference is converted to bool and returned by copy:
auto lambda = [](unsigned int param) -> bool
                                     // ^^^^
{   
    std::bitset<10> bits(param);
    std::cout << "inside lambda bits[8] = " << bits[8] << std::endl; 
    return bits[8];
};

Here's a demo

  1. Make the std::bitset in the lambda const so that it calls the const overload of operator[], which returns a bool:
auto lambda = [](unsigned int param)
{   
    std::bitset<10> const bits(param);
                 // ^^^^^
    std::cout << "inside lambda bits[8] = " << bits[8] << std::endl; 
    return bits[8];
};

Here's a demo.

  1. Store the value of bits[8] as a bool, and return that:
auto lambda = [](unsigned int param)
{   
    std::bitset<10> bits(param);
    std::cout << "inside lambda bits[8] = " << bits[8] << std::endl; 
    bool b = bits[8];
 // ^^^^^^
    return b;
};

Here's a demo.

cigien
  • 57,834
  • 11
  • 73
  • 112