13

std::vector has a constructor where passing a single argument of size_type count should size the vector with count default-constructed elements. But the following code fails with a bad_alloc exception after a bad conversion:

#include <vector>

struct Inner {
  int foo;
  char buf[256];
};

template <typename Type>
struct Outer
{
  typedef std::vector<Inner> BufContainer;
  typedef typename BufContainer::size_type BufIndex;
  BufContainer bufs1;
  BufContainer bufs2;
  const BufIndex BUFCOUNT = 32;

  Outer() :
    bufs1(32),       // fine
    bufs2(BUFCOUNT)  // bad_alloc
  { }
};

int main() {
  Outer<int> outer;
}

When I look in the debugger, I can see an incorrect conversion has occurred on that second vector constructor:

#13 0x0000000000400bf1 in Outer<int>::Outer (this=0x7ffdc59570c0) at wtf.cc:22
22          bufs2(BUFCOUNT)
(gdb) down
#12 0x0000000000400d6e in std::vector<Inner, std::allocator<Inner> >::vector     (this=0x7ffdc59570d8, __n=140727918359008, __a=...) at /usr/local/gcc-4.9.1/include/c++/4.9.1/bits/stl_vector.h:278
278       : _Base(__n, __a)
(gdb) list
273        *  This constructor fills the %vector with @a __n default
274        *  constructed elements.
275        */
276       explicit
277       vector(size_type __n, const allocator_type& __a = allocator_type())
278       : _Base(__n, __a)
279       { _M_default_initialize(__n); }
(gdb) print __n
$1 = 140727918359008

std::vector::size_type is simply a typedef from size_t. I don't understand why my defined constant BUFCOUNT results in that rolled-around value inside the constructor, and would appreciate anyone helping me find the obvious thing I'm missing.

1
  • 5
    (1) Copy/paste your MCVE into Coliru; (2) Read the warning; (3) ?? (4) all teh profitz Commented Jun 30, 2017 at 12:49

1 Answer 1

31

BUFCOUNT is not static, which means it's an instance data member (just like bufs1, bufs2, etc. Non-static data members are initialised in the order of their declaration within the class. This means that bufs1 and bufs2 will be initialised before BUFCOUNT. The initialisation of bufs2 therefore uses the as-yet-unitialised value of BUFCOUNT (in other words, has Undefined Behaviour).

Since it makes zero sense to have each Outer object store the same BUFCOUNT integer inside it, you might want to make BUFCOUNT static.

Sign up to request clarification or add additional context in comments.

9 Comments

I knew it would be something straightforward. I need another cup of coffee. Thank you so much.
I'm surprised that your compiler didn't warn you about this, @John. Do you have your warnings turned off for some reason?
I'm surprised, too. I just ran it again under gcc 4.9.1 and 5.3.0 with -Wall and -pedantic and they were silent. Clang 8.1.0 found it, though.
@cat The junk from the stack is a huge number, so the allocator simply runs out of memory trying to satisfy the request. This is what bad_alloc means, after all. (Of course, it could also by chance be a small number, in which case there would not be an immediate error.)
@JohnS: Beware with gcc, a number of the unused warnings are performed during optimizations analyses and therefore only run when building with some optimizations on. On the other hand, in Clang warnings and optimizations are independent, thus you get the full benefit of all warnings even at -O0.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.