Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

g++4.9 bug in allowing std::vector<C_type_array>

Consider the following code:

#include <iostream>
#include <vector>
#include <array>

using namespace std;

typedef double (C_array)[10];

int main()
{ 
    std::vector<C_array> arr(10);

    // let's initialize it
    for (int i = 0; i < 10; i++)
        for (int j = 0; j < 10; j++)
            arr[i][j] = -1;

    // now make sure we did the right thing
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10; j++)
        {
            cout << arr[i][j] << " ";
        }
        cout << endl;
    }
}

I just found out from @juanchopanza https://stackoverflow.com/a/25108679/3093378 that this code should not be legal, since a plain old C-style array is not assignable/copyable/movable. However g++ flies through the code, even with -Wall -Wextra -pedantic. clang++ doesn't compile it. Of course if I try to do something like auto arr1 = arr;, it fails under g++, as it doesn't know how to copy arr into arr1.

I used g++4.9 from macports under OS X Mavericks. Live code here: http://goo.gl/97koLa

My questions are:

  1. Is this code illegal according to the standard?
  2. Is g++ so buggy? I keep finding lots of simple examples in which g++ blindly compiles illegal code, last was yesterday user-defined conversion operators precedence, compiles in g++ but not clang++ , and without too much effort, just experimenting with C++ for fun.
like image 534
vsoftco Avatar asked Aug 03 '14 21:08

vsoftco


1 Answers

Your code is not valid C++03. First, the header <array> is not part of the C++03 standard library but it is also not needed here. Second, the construction of the vector object tries to call the constructor

explicit vector(size_type n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type());

However, the initialization of val fails for the same reason why you cannot write

C_array foo = C_array();

To the best of my understanding paragraph 2 in section 5.2.3 of the C++03 standard allows this notation only for non-array types:

The expression T(), where T is a simple-type-specifier (7.1.5.2) for a non-array complete object type or the (possibly cv-qualified) void type, creates an rvalue of the specified type, which is value-initialized (8.5; no initialization is done for the void() case).

Furthermore, g++-4.9.0 does also refuse to compile the code unless -std=c++11 is provided on the command line:

foo.cpp: In constructor ‘std::vector<_Tp, _Alloc>::vector(std::vector<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = double [10]; _Alloc = std::allocator<double [10]>; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = double [10]; std::vector<_Tp, _Alloc>::allocator_type = std::allocator<double [10]>]’:
foo.cpp:11:32: error: functional cast to array type ‘std::vector<double [10]>::value_type {aka double [10]}’
 std::vector<C_array> arr(10);
...

As for C++11 the vector container offers an additional fill constructor:

explicit vector (size_type n);

This constructor requires that the template type be default-constructible (see section 23.3.6.2). To the best of my understanding this requirement is also not met in C++11 (see section 17.6.3.1) since in order to meet the requirement the expression C_array() must create a temporary object, which is also not valid in C++11 (again see section 5.2.3). I don't know whether the standard actually requires the compiler to reject the code or whether the compiler is allowed to compile it if one of the requirements is not met but the implementation of the standard library just does not need it. Maybe people who know more about C++11 can fill in the gaps here.

Aside from all that it is in my opinion not a good idea to try to use an array as a container element type since other container requirements are not met. For example C_array is not copy-insertable and thus the vector cannot be copied.

Concerning your second question: Feel free to browse the gcc bugzilla database at https://gcc.gnu.org/bugzilla/. However, accepting invalid code can also be on purpose e.g. in order to not break legacy code.

like image 156
user1225999 Avatar answered Sep 22 '22 10:09

user1225999