Gabriel Staples
Gabriel Staples

Reputation: 52489

Initializing std::vector<int> with square brackets [] inside; what is happening?

Background information about what inspired my question:

I learned about Designated Initializers in C (see here and here: https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html), which are awesome, and allow you to initialize C arrays in C like this, which is awesome:

int my_array[] = 
{
    [MY_ENUM1] = 7,
    [MY_ENUM5] = 6,
};

I tried it in C++ and it doesn't work (see my comments under the answer linked-to above). Bummer. I tried it in a C++ std::vector and got behavior I don't understand. What is happening here?

The crux of my question:

What are the [7] = 12 and [10] = 15 doing in my example? What is going on there? Why does that compile? Why is the output the way it is?

I just compiled the below code with -Wall -Wextra -Werror -Wpedantic, and it still compiles with zero warnings. -Wpedantic is one I almost never use, and do not recommend, because it turns off compiler extensions, which I like to keep on. Yet, I still get no warnings with that unusual [7] = 12 syntax.

Update: something seems to be wrong with onlinegdb's ability to accept my compiler flags. With -Wpedantic I do see the warning when I run it locally:

eRCaGuy_hello_world/cpp$ g++ -Wall -Wextra -Werror -Wpedantic -O3 -std=c++17 vector_with_square_brackets.cpp -o bin/a && bin/a
vector_with_square_brackets.cpp:19:5: error: ISO C++ does not allow C99 designated initializers [-Werror=pedantic]
     [7] = 12, // Why does this "work" here? What is happening?
     ^
vector_with_square_brackets.cpp:20:5: error: ISO C++ does not allow C99 designated initializers [-Werror=pedantic]
     [10] = 15,
     ^
cc1plus: all warnings being treated as errors

WithOUT -Wpedantic, however, I see no warnings nor errors:

eRCaGuy_hello_world/cpp$ g++ -Wall -Wextra -Werror -O3 -std=c++17 vector_with_square_brackets.cpp -o bin/a && bin/a
1
2
3
12
15
4

...yet the output still doesn't follow the rules of Designated Initializers either. Am I in the realm of something like a compiler bug? I'd still like more answers and clarity.

My g++ --version is g++ (Ubuntu 8.4.0-1ubuntu1~18.04) 8.4.0.

See especially my comment in the code below:

Run it online: https://onlinegdb.com/FZ2YdZXJe (gcc compiler set to C++17)

#include <iostream>
#include <vector>

std::vector<int> v =
{
    1,
    2,
    3,
    [7] = 12, // Why does this "work" here? What is happening?
    [10] = 15,
    4,
};

int main()
{
    for (int i : v)
    {
        std::cout << i << "\n";
    }
    printf("\n");

    return 0;
}

Output:

1
2
3
12
15
4

Also, I was actually expecting the output to look like this, assuming it were to act like "designated initializers" in C arrays. Since I didn't get this output, something else I don't understand must be going on (hence this question).

1
2
3
0
0
0
0
12
0
0
15
4

Update: it appears to be a GCC compiler bug

...which exists in version 8.4 (the version I'm using) but was fixed by version 9.1. See the comment below this answer:

I would say, this was a general issue with previous versions of the compilers, because GCC 8.4 does compile it: https://godbolt.org/z/xqYq6jeb8. Since version 9.1, errors starts to occur. – Erdal Küçük

Upvotes: 3

Views: 608

Answers (1)

Quick answer

Why does this "work" here? What is happening?

It does not, it is non standard. It's a compiler bug. GCC version 8.4 (the version of the OP) compiles without any warnings and or errors (see: https://godbolt.org/z/xqYq6jeb8). After version 9.1, errors will start to occur.

Details

For a short overview, have a look at: https://www.modernescpp.com/index.php/designated-initializers.

Especially at the paragraph: https://www.modernescpp.com/index.php/designated-initializers#h2-1-differences-between-c-and-c


Have a look at the GCC page: https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html

There you can read the following:

This extension is not implemented in GNU C++.


Since you're working with std::vector, have a look at how a vector can be constructed: https://en.cppreference.com/w/cpp/container/vector/vector

The constructor listed in no. 10 vector(std::initializer_list<T> init) allows the initialization like this:

//Constructs the container with the contents of the initializer list init. 
std::vector<int> v = {1, 2, 4};

The documentation to initializer-list can be found here: https://en.cppreference.com/w/cpp/utility/initializer_list


General initialization in C++: https://en.cppreference.com/w/cpp/language/initialization

The initialization type you're most interested in would be: Aggregate initialization

There, in the section Designated initializers, you will be able to read the following:

Note: out-of-order designated initialization, nested designated initialization, mixing of designated initializers and regular initializers, and designated initialization of arrays are all supported in the C programming language, but are not allowed in C++.


After some discussions, we found out, that the issues have to do something with the different implementations of the compiler (versions).

Since the standard and e.g. the compiler GCC states, that designated initializers are supported in the C but not in the C++ language, still GCC version 8.4 (the version of the OP) compiles without any warnings and or errors (see: https://godbolt.org/z/xqYq6jeb8). After version 9.1, errors will start to occur.

Upvotes: 2

Related Questions