Bit array implementation
Don't write a function to return a constant

You don't need uint_size(), as the returned value never changes (for a given target platform).  You can replace it with

#include &lt;climits&gt;
static const std::size_t uint_bits = CHAR_BIT * sizeof (unsigned int);


Don't require a call to init()

The constructor should fully initialize the object; just move the body of init() there instead.

Use integer operations on integers

Instead of using std::ceil to round up division, we can do this in integer arithmetic by adding one less than the divisor before dividing:

    elements_ = (bits + uint_bits - 1) / uint_bits;


Given that we know the number of bits, we can always compute the number of elements when we need it; you might consider the trade-off between storing and computing elements_.

Obey the Rule of Five (or Rule of Zero)

You allocate memory in the constructor, but don't provide copy/move constructors, nor an assignment operator, so you run the risk of double delete[].  The easiest fix is to use a standard container as the storage; you might also consider using a smart pointer to the storage.  As a last resort, you could manage the memory yourself, but I'd advise against that.

Use an unsigned type for indexing

You can avoid needing to check for negative index values by accepting an unsigned integer type in the methods.  I recommend std::size_t as the standard type usually used for that.

Return by value when possible

void size(int&amp; bits) const;


is better written as

std::size_t size() const;




My version

Working replacement code:

#include &lt;climits&gt;
#include &lt;stdexcept&gt;
#include &lt;vector&gt;

class Bitarray1D {
    using Element = unsigned int;

    class Bit {
        Element&amp; element;
        const Element mask;
    public:
        Bit(Element&amp; element, Element mask) : element{element}, mask{mask} {}
        Bit(const Bit&amp; other) : Bit{other.element, other.mask} {}
        operator bool() const { return element &amp; mask; }
        Bit&amp; operator=(bool b) { element = b ? element | mask : element &amp; ~mask; return *this; }
        Bit&amp; operator=(const Bit&amp; other) { return this-&gt;operator=(bool(other)); }
    };

    static const std::size_t element_bits = CHAR_BIT * sizeof (Element);

    std::size_t bits;
    std::vector&lt;Element&gt; array;

public:
    Bitarray1D(std::size_t bits);
    ~Bitarray1D() = default;

    std::size_t size() const;

    Bit operator[](std::size_t index);

};

Bitarray1D::Bitarray1D(std::size_t bits)
    : bits{bits},
      array{}
{
    // rounded-up division
    array.resize((bits + element_bits - 1) / element_bits);
}

Bitarray1D::Bit Bitarray1D::operator[](std::size_t index) {
        if (index &gt;= bits)
            throw std::out_of_range("Index out of range");
        return Bit(array[index / element_bits], 1u &lt;&lt; (index % element_bits));
}


int main()
{
    Bitarray1D bits{15};
    bits[0] = 0;
    bits[2] = bits[1] = 1;
    return bits[0] + bits[1] + bits[2] != 2;
}