7

Possible Duplicate:
Why vector<bool>::reference doesn’t return reference to bool?

I used to think that with std::vector::operator[] we get deep copies of the accessed item, but it seems that it is not always true. At least, with vector<bool> the following test code gives a different result:

#include <iostream>
#include <vector>
using namespace std;

template <typename T>
void Test(const T& oldValue, const T& newValue, const char* message)
{
    cout << message << '\n';

    vector<T> v;
    v.push_back(oldValue);
    cout << " before:  v[0] = " << v[0] << '\n';

    // Should be a deep-copy (?)       
    auto x = v[0];   
    x = newValue;

    cout << " after:   v[0] = " << v[0] << '\n';
    cout << "-------------------------------\n";
}

int main()
{
    Test<int>(10, 20, "Testing vector<int>");
    Test<double>(3.14, 6.28, "Testing vector<double>");
    Test<bool>(true, false, "Testing vector<bool>");
}

Output (source code compiled with VC10/VS2010 SP1):

Testing vector<int>
 before:  v[0] = 10
 after:   v[0] = 10
-------------------------------
Testing vector<double>
 before:  v[0] = 3.14
 after:   v[0] = 3.14
-------------------------------
Testing vector<bool>
 before:  v[0] = 1
 after:   v[0] = 0
-------------------------------

I would have expected that v[0] after the x = newValue assignment would still be equal to its previous value, but this seems not true. Why is that? Why is vector<bool> special?

Community
  • 1
  • 1
Mr.C64
  • 41,637
  • 14
  • 86
  • 162
  • Actually `vector` is quite special by design, see: http://www.cplusplus.com/reference/vector/vector-bool/ – Hvordan har du det Jan 30 '13 at 11:58
  • 2
    It is neither a `vector`, nor contains `bool` values. – Peter Wood Jan 30 '13 at 12:10
  • 2
    This is a very nice example how type deduction can shoot you in the foot and how the solutions to the problem aren't obvious. – pmr Jan 30 '13 at 12:11
  • 2
    @pmr it's not the type deduction which is at fault here, it's the non-generic behavior of supposedly generic code. they Committee should have renamed `vector` to `bitvector` (and I believe there were some proposals for that) – TemplateRex Jan 30 '13 at 12:14
  • 2
    @rhalbersma The code would be working as expected if you would use `T` or `vector::value_type` instead of `auto`. I believe earlier specs required `operator[]` of a container to return something convertible to a `T&`, but that doesn't seem to be the case for C++11 anymore. – pmr Jan 30 '13 at 12:18
  • @pmr: I've added the `auto` tag, too. – Mr.C64 Jan 30 '13 at 12:21
  • @PeterWood: Then better changing its name. – Mr.C64 Jan 30 '13 at 12:21
  • 2
    See also http://isocpp.org/blog/2012/11/on-vectorbool – Jonathan Wakely Jan 30 '13 at 12:22

3 Answers3

21

vector<bool> is a hideous abomination and special. The Committee specialized it to pack bits, therefore it does not support proper reference semantics, as you cannot refer to a bit, this means that it has a non-conforming interface and does not actually qualify as a Standard Container. The solution that most people use is simply to never, ever, use vector<bool>.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 1
    As noted in [this blog post](http://isocpp.org/blog/2012/11/on-vectorbool) (pointed by @JonathanWakely), having an array of bits data structure can be good. Probably the choice of the name `vector` is not good, if the "public interface" is kind of different than usual `vector`. – Mr.C64 Jan 30 '13 at 12:30
  • 1
    It's very bad to specialize a container like this. There should be `dynamic_bitset`. – Puppy Jan 30 '13 at 12:41
  • 1
    @DeadMG there is, in Boost. – TemplateRex Jan 30 '13 at 13:04
  • `vector` or similar is a decent alternative – Inverse Feb 05 '13 at 19:24
  • I would prefer `deque`, meets all I need - also supports [], dynamic, compatible with old C++ compiler, a real STL container – Deqing Jun 20 '14 at 02:58
6

vector<bool>::operator[] neither yields a bool nor a reference to a bool. It just returns a little proxy object that acts like a reference. This is because there are no references to single bits and vector<bool> actually stores the bools in a compressed way. So by using auto you just created a copy of that reference-like object. The problem is that C++ does not know that this object acts as a reference. You have to force the "decay to a value" here by replacing auto with T.

Mr.C64
  • 41,637
  • 14
  • 86
  • 162
sellibitze
  • 27,611
  • 3
  • 75
  • 95
4

operator[] returns a T& for every value of T except for bool, where it gives a reference proxy. See this old column by Herb Sutter on why using vector<bool> in generic code is bad idea (and why it is not even a container). There is also a special Item about it in Effective STL by Scott Meyers, and tons of questions on it here at SO.

Community
  • 1
  • 1
TemplateRex
  • 69,038
  • 19
  • 164
  • 304