Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I can no longer assign char[M][N] types into a std::vector on gcc 4.9

Tags:

c++

gcc

c++11

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?

like image 604
spraff Avatar asked Dec 29 '14 20:12

spraff


1 Answers

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.

like image 140
T.C. Avatar answered Oct 03 '22 01:10

T.C.