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

1

3

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

Laoag answered 27/1, 2022 at 4:8 Comment(4)
Standard C++ doesn't support designated initialisers before C++20 and the support in C++20 differs from C. However, some C++ compilers support some vendor-specific subset of C features as non-standard extension by default (i.e. need to specifically configure your compiler (or use particular command line options when compiling) to turn off those features). You're probably using one of those compilers. Using non-standard features increases risk of maintaining your code (e.g. more effort when porting to a different compiler, an update of your compiler may also change what is supported)Cyclist
I would say, this was a general issue with previous versions of the compilers, because GCC 8.4 does compile it: godbolt.org/z/xqYq6jeb8. Since version 9.1, errors starts to occur.Blanketyblank
@ErdalKüçük, I think that's the answer. Can you add that comment above to your answer? I think that's the core part of the answer to my question: gcc 8.4 has a compiler bug, or deviant compiler behavior, or however it should be worded, and they fixed it since version 9.1.Laoag
I've added the comment to my answer.Blanketyblank
T
2

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.

Tangible answered 27/1, 2022 at 4:57 Comment(8)
This confirms what I already know: that "designated initializers" don't work in C++, but fails to answer the main part of my question, which is: what is [7] = 12 doing in my example? It compiles. It runs. It does something, but that is that something, and why?Laoag
It does nothing, it is non standard. It is not worth thinking about. My compiler (GCC 11) refuses to compile it.Blanketyblank
Non-standard means it may be a gcc extension. I use gcc extensions all the time. In embedded programming sometimes they are essential, or practically so. If it is a gcc extension, I'd still like to know. Not only does it compile and run, it compiles with zero warnings.Laoag
I just compile with -Wall -Wextra -Werror -Wpedantic, and it still compiles with zero warnings. -Wpedantic is one I almost never use, because it turns off compiler extensions, which I like to keep on.Laoag
No, GCC states that this extension is not implemented in GNU C++. Maybe other compilers but IT IS NOT C++ STANDARD. Your question has only the C++ and no other compiler specific tag.Blanketyblank
Compiled with: g++ -Wall -Wextra -Werror -Wpedantic -o main main.cpp. Output: error: ISO C++ does not allow C99 designated initializers [-Werror=pedantic] and error: designated initializers cannot be used with a non-aggregate type ‘std::vector<int>Blanketyblank
I think you're running the wrong code. I've updated my question since I can see where the confusion is coming from. Try it again.Laoag
No, the same result. Because, neither the standard nor the compiler does support it.Blanketyblank

© 2022 - 2024 — McMap. All rights reserved.