Search code examples
c++vectorbitset

Use of std::vector results in unknown output C++


I'm unable to figure out why the output I received isn't just "00110" but has other giberrish characters in it. Not sure what's wrong with my vector push_back.. It definitely makes sense to me. If I changed it to std::string implementation, it would give a correct output. But in this case, I would need to use vector for proper encapsulation of the object's state. I've been debugging for a few hours now, but still can't find out why. Hope anyone is able to help! Thanks! Note: main() can't be modified.

#include <iostream>    
#include <vector>     

template<size_t NumBits>
class bitsetts
{
private:
    static const unsigned int NO_OF_BITS = CHAR_BIT * sizeof(int); //32 bits
    static const unsigned NumBytes = (NumBits - 7) /8;
    unsigned char array[NumBytes];
public:
    bitsetts() {  }

    void set(size_t bit, bool val = true) {
        if (val == true)
        {
            array[bit] |= (val << bit  );
        }
        else
        {
            array[bit] &= (val << bit  );

        }
    }

    bool test(size_t bit) const {
        return array[bit] & (1U << bit  );
    } 
    const std::string to_string()
    {
        std::vector<char> str;

        for (unsigned int i=NumBits; i-- > 0;)
            str.push_back('0' + test(i));

        return str.data();
    } 
    friend std::ostream& operator<<(std::ostream& os, const bitsetts& ob)
    {
        for (unsigned i = NumBits; i-- > 0;) 
        os << ob.test(i);
        return os << '\n';
    }
};

int main()
{
    try
    {
        bitsetts<5> bitsetts;
        bitsetts.set(1);
        bitsetts.set(2);

        const std::string st = bitsetts.to_string();
        if (st != "00110")
        {
            std::cout << st << std::endl;
            throw std::runtime_error{ "-" };
        }
    }
    catch (const std::exception& exception)
    {
        std::cout << "Conversion failed\n";
    }
}

Solution

  • You are filling the std::vector with char values and then constructing a std::string from the raw char data using the std::string constructor that takes a single const char* parameter. That constructor expects the char data to be null-terminated, but you are not pushing a null terminator into your vector, which is why you get extra garbage on the end of your std::string.

    So, either push a null terminator into the vector, eg:

    const std::string to_string()
    {
        std::vector<char> str;
    
        for (unsigned int i=NumBits; i-- > 0;)
            str.push_back('0' + test(i));
    
        str.push_back('\0'); // <-- add this!
    
        return str.data();
    }
    

    Or, use a different std::string constructor that can take the vector's size() as a parameter, eg:

    const std::string to_string()
    {
        std::vector<char> str;
    
        for (unsigned int i=NumBits; i-- > 0;)
            str.push_back('0' + test(i));
    
        return std::string(str.data(), str.size()); // <-- add size()!
    }
    

    On a side note: your to_string() method should be marked as const, eg:

    const std::string to_string() const
    

    Which would then allow you to use to_string() inside of your operator<<, eg:

    friend std::ostream& operator<<(std::ostream& os, const bitsetts& b)
    {
        return os << b.to_string() << '\n';
    }