Is there a way to initialize a vector by index...
In C there is: see What do square brackets mean in array initialization in C? , with something called "Designated Initializers".
In C++ there is not, but I have presented a work-around I like, below. See cppreference.com here, under the "Designated initializers" section near the bottom: https://en.cppreference.com/w/cpp/language/aggregate_initialization
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++.
struct A { int x, y; };
struct B { struct A a; };
struct A a = {.y = 1, .x = 2}; // valid C, invalid C++ (out of order)
int arr[3] = {[1] = 5}; // valid C, invalid C++ (array)
struct B b = {.a.x = 0}; // valid C, invalid C++ (nested)
struct A a = {.x = 1, 2}; // valid C, invalid C++ (mixed)
See also the GCC documentation here (emphasis added):
In ISO C99 you can give the elements in any order, specifying the array indices or structure field names they apply to, and GNU C allows this as an extension in C90 mode as well. This extension is not implemented in GNU C++.
And see also my question here: Initializing std::vector with square brackets [] inside; what is happening?
So, you can use std::map
or std::unordered_map
to do this, but I want really fast access, and accessing a contiguous piece of memory such as a C-style array, C++ std::array
, or C++ std::vector
via a simple index will be much faster. So, what I have settled on as a work-around solution is this:
In header.h:
WARNING: be sure to set the size! operator[]
for std::vector
does NOT automatically add members if you index past the end of the vector. See: https://en.cppreference.com/w/cpp/container/vector/operator_at:
(Regarding std::vector<T,Allocator>::operator[]
; emphasis added):
Unlike std::map::operator[]
, this operator never inserts a new element into the container. Accessing a nonexistent element through this operator is undefined behavior.
#include <vector>
std::vector<int> v(5); // WARNING: set the size you need!
In source.cpp:
v[0] = 1;
v[1] = 2;
v[2] = 3;
v[3] = 4;
v[4] = 5;
This is not ideal because it doesn't allow you to make your vector const
or constexpr
, but that's okay. It's a worthwhile tradeoff I think in the case of trying to make fast maps with crystal clear mapping. Ex:
(Use a C style enum
here, NOT a C++ style enum class
--more on that in my answer here: How can I iterate over an enum?)
enum fruits
{
FRUITS_APPLE = 0,
FRUITS_BANANA,
FRUITS_PEAR,
FRUITS_LEMON,
FRUITS_KIWI,
/// Not a valid value; this is the number of members in this enum
FRUITS_count,
};
// Now you can initialize your std::vector<> in your .cpp file clearly
// (with crystal-clear enum-based indexing, or mapping) like this.
// Think of this as a key:value pair, with the enum being the key and
// the value of course being the value.
v[FRUITS_APPLE] = 1;
v[FRUITS_BANANA] = 2;
v[FRUITS_PEAR] = 3;
v[FRUITS_LEMON] = 4;
v[FRUITS_KIWI] = 5;
Note that if the object is a fixed size, you are better off using std::array
instead:
Declaration of the array, to map from enum fruits
to integers, for example:
#include <array>
std::array<int, FRUITS_count> fruitsArray;
Load it with values:
fruitsArray[FRUITS_APPLE] = 1;
fruitsArray[FRUITS_BANANA] = 2;
fruitsArray[FRUITS_PEAR] = 3;
fruitsArray[FRUITS_LEMON] = 4;
fruitsArray[FRUITS_KIWI] = 5;
Side note: if you ever need to make the data type constexpr
, std::array
and C-style arrays can both be made constexpr
, but std::vector
canNOT--it can only be const
at best.
See also:
- [my answer] How can I iterate over an enum?