I was using gcc 4.8 until I upgraded Ubuntu, now I have gcc-4.9.1-16. Code which used to compile without warnings and run fine now no longer compiles.
static const unsigned WIDTH = 16;
static const unsigned VSCALE = 1;
static const unsigned HEIGHT = WIDTH / VSCALE;
static const unsigned FOOTER = 2;
typedef char Row [WIDTH + 1];
typedef Row World [HEIGHT - FOOTER];
std :: vector <World> m_levels;
World levels [] =
{
{
" ",
" ",
" ",
" ",
" ",
" ### ### ",
" ",
"1122112211221122",
" 33003300330033 ",
"1122112211221122",
" 33003300330033 ",
" ",
" ",
" "
},
{
" 44 ",
" 555 55 ",
" 66 66 ",
" 777 777 ",
" 66 66 ",
" 777 777 ",
" 66# #66 ",
" 777 # # 777 ",
" 66 # # 66 ",
" 777 # # 777 ",
" 66# #66 ",
" 555 55 ",
" 44 ",
" "
}
};
// The next line is line 68
m_levels .assign (std :: begin (levels), std :: end (levels));
The final line errors with
.../foo.cpp:68:62: required from here /usr/include/c++/4.9/bits/stl_algobase.h:373:4: error: static assertion failed: type is not assignable
.../foo.cpp:68:62: required from here /usr/include/c++/4.9/bits/stl_construct.h:75:7: error: parenthesized initializer in array new [-fpermissive]
The compile options have not changed, they are -W -Wall -Wextra -Werror -pedantic --std=c++0x as far as I can tell only gcc has changed.
Why does this code no longer compile?
The bare minimum requirement on value types for standard containers is that they must be Erasable. For the default allocator, this translates to the requirement that given value_type *p;, p->~value_type(); must be well-formed.
If value_type is a class type, it simply invokes the destructor, and is well-formed if the destructor is not deleted and is accessible. If value_type denotes a scalar type, p->~value_type(); is also valid and a no-op (this is called a pseudo destructor call). However, if value_type is an array type, then p->~value_type(); is invalid.
Hence, built-in arrays are never valid value types for standard containers, at least when the default allocator is used. (Various other container operations place more requirements on the value type; built-in arrays would run afoul of at least some of them since they are not assignable.)
Instantiating a standard library template with types that do not satisfy the requirements of that template results in undefined behavior. It appears that libstdc++ by happenstance didn't diagnose your error until the version that shipped with GCC 4.9.
The fix, by the way, is simple. Just use std::array.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With