Search code examples
c++gccclangstdstd-bitset

Difference of behavior between libstdc++ and libc++: operator>> on bitset


Consider the following code:

#include <bitset>
#include <sstream>
#include <iostream>

int main(int argc, char* argv[])
{
    std::stringstream stream;
    std::bitset<1> bitset(1);
    std::cout<<"before = "<<bitset[0]<<std::endl;
    stream<<"4";
    stream>>bitset;
    std::cout<<"after = "<<bitset[0]<<std::endl;
    return 0;
}

Compiled under g++ with libstdc++, the result is:

> g++ bitset_empty.cpp -o bitset_empty
> ./bitset_empty 
before = 1
after = 1

Compiled under clang++ with libc++, the result is:

> clang++ -stdlib=libc++ bitset_empty.cpp -o bitset_empty
> ./bitset_empty 
before = 1
after = 0

Which one is right? Both (because of undefined behavior)? GCC? Clang?


Solution

  • From my understanding, libc++ is right here, but it's not the only correct behavior.

    N4140 §20.6.4 [bitset.operators]

    Effects: Extracts up to N characters from is. Stores these characters in a temporary object str of type basic_string<charT, traits>, then evaluates the expression x = bitset<N>(str). Characters are extracted and stored until any of the following occurs:

    • N characters have been extracted and stored;
    • end-of-file occurs on the input sequence;
    • the next input character is neither is.widen(’0’) nor is.widen(’1’) (in which case the input character is not extracted).

    If no characters are stored in str, calls is.setstate(ios_base::failbit) (which may throw ios_base::failure (27.5.5.4))

    It's important to note that x = bitset<N>(str) is not conditional. If ios_base::failure is not thrown, then that is the expression executed. And bitset<N>(""s) (that is, of an empty string) is 0.

    Thus, in my understanding, your bitset should be zeroed or the aforementioned exception should've been thrown.

    If no exception is thrown, you may want to test if your operation was successful (by testing the returned stream).