70

Does someone know the way to define constant-sized vector?

For example, instead of defining

std::vector<int>

it will be

std::vector<10, int>

It should be completely cross-platformed. Maybe an open source class?

CinCout
  • 9,044
  • 11
  • 51
  • 63
Iron-Eagle
  • 1,597
  • 2
  • 14
  • 32

7 Answers7

70

The std::vector can always grow dynamically, but there are two ways you can allocate an initial size:

This allocates initial size and fills the elements with zeroes:

std::vector<int> v(10);
v.size(); //returns 10

This allocates an initial size but does not populate the array with zeroes:

std::vector<int> v;
v.reserve(10);
v.size(); //returns 0
svelten
  • 1,309
  • 12
  • 11
  • if it was a vector of some user defined type that was given a initial size, what would it be initialized to? – simplename Feb 15 '18 at 15:31
  • The answers below that say to use std::array should be accepted – Michael Mar 15 '18 at 19:06
  • 1
    I came here looking for this answer. The question looks a lot like someone looking for an `std::array`, but I for one do not know my size at compile time and do want to just allocate a certain number of elements fixed. – scravy Sep 24 '18 at 14:50
  • `vector v(10)` --> *allocates initial size and fills the elements with zeroes* i.e. **allocates the space and constructs the object.** while `v.reserve(10)` --> *allocates an initial size but does not populate the array with zeroes.* i.e. **just allocates the space but does not construct the object** -- very important! – Milan Apr 12 '22 at 21:31
66

There is no way to define a constant size vector. If you know the size at compile time, you could use C++11's std::array aggregate.

#include <array>

std::array<int, 10> a;

If you don't have the relevant C++11 support, you could use the TR1 version:

#include <tr1/array>

std::tr1::array<int, 10> a;

or boost::array, as has been suggested in other answers.

juanchopanza
  • 216,937
  • 30
  • 383
  • 461
  • 6
    Although be aware that `array` is different from `vector` in that the data is contained inside the object. For 10 ints you may never notice the difference, but for large arrays you might (for example) notice that they do not have `O(1)` `swap`, whereas large vectors do. – Steve Jessop Jun 21 '12 at 09:24
  • 7
    Also be aware that an array doesn't have a concept of `size` vs `capacity` like vector does. In an array `size` == `max_size`. That is, you can't create an array of size 10 (ie: space for 10 possible elements), but populate only 5 and expect `size` to return 5. – Steve Lorimer Feb 19 '16 at 18:12
  • Also note that std::array does not cast to a generic run time size. If you want to pass different sized arrays to a function, you would have to pass in both the data() and size() – Michael Mar 15 '18 at 22:21
  • @SteveLorimer *"... but for large arrays you might (for example) notice that they do not have O(1) swap, whereas large vectors do."* -- could you please share resources/references that I can look into to understand more about this? Thank you in advance! – Milan Mar 11 '22 at 22:00
  • 1
    @Milan for a vector you swap just the pointer to the underlying array, whereas unless the array is allocated on the heap (thereby allowing you to swap just the pointer to the array) you have to move all the elements. Read more here: https://stackoverflow.com/a/26312602/955273 – Steve Lorimer Mar 12 '22 at 07:00
  • @SteveLorimer Thanks for further clarification. But, I'm still super confused: if I initialize a vector like this: `std::vector vec1 = {1, 2, 3}`, it will/should be allocated on the stack only, right? It will get allocated on the heap, only if I initialize it like this: `std::vector *vec2 = new std::vector({1, 2, 3})`, isn't it? Please correct me if I'm mistaken. Thanks again! – Milan Mar 22 '22 at 13:56
  • 1
    @Milan yes and no - the vector object itself will be stored on the stack, but *internally* it has dynamic storage which is allocated on the heap. The reason for this is that a vector does not have a fixed number of items it can store; you can change the number of elements at run time. As the number of items in the vector increases it may need to allocate a new larger array for its internal storage (dynamically/"on the heap"). So when you `swap` 2 vectors, it's the pointers to these internal arrays which get swapped – Steve Lorimer Mar 22 '22 at 14:30
  • @SteveLorimer Thank you so much for such a quick response and detailed explanation. I appreciate that. Sorry, but the further question (hopefully the last one): If the vector internally has dynamic storage then does it ever/even make any sense to initialize the vector object itself on the heap using `new`? (I think initializing using the smart pointers is a whole different matter here, correct?) – Milan Mar 22 '22 at 15:16
  • 1
    @Milan in general no, I would not see much sense in creating the vector itself on the heap, unless you wanted to differentiate between a "null" vector and an empty vector... but for that you would probably be better served using `std::optional` – Steve Lorimer Mar 22 '22 at 15:23
14

If you want a fixed compile-time specified size (ala std::array<T, N>), but you want to be able to populate the vector with varying numbers of elements between 0 and N, then a good option is eastl::fixed_vector.

std::vector:

The size of a std::vector is dynamic - it will allocate required storage dynamically, and you cannot limit the size and enforce an error.

You can however reserve a certain size, and then add elements up that size before it needs to allocate new storage.

vector.size() is initially 0, and increases as you add elementss

std::array:

The size of a std::array is a compile-time constant - it will allocate required storage statically, and you cannot change the size.

array.size() is always the size of the array, and is equal to array.max_size()

eastl::fixed_vector:

The size of an eastl::fixed_vector can be either static or dynamic.

It will allocate a certain number of elements initially, and then if you allow dynamic growth, will allocate dynamically if required.

For the purpose you originally asked for, you can disable growth (via bEnableOverflow in the template instantiation below)

fixed_vector.size() is initially 0, and increases as you add elements.

template<typename T, 
         size_t nodeCount, 
         bool bEnableOverflow = true, 
         typename OverflowAllocator = 
                      typename eastl::type_select<bEnableOverflow,
                                                  EASTLAllocatorType, 
                                                  EASTLDummyAllocatorType>::type>
class fixed_vector;

Simple example:

#include <iostream>
#include <vector>
#include <array>
#include "EASTL/fixed_vector.h"

int main()
{
    std::vector<int> v;
    v.reserve(10);
    std::cout << "size=" << v.size() << " capacity=" << v.capacity() << '\n';

    std::array<int, 10> a;
    std::cout << "size=" << a.size() << " capacity=" << a.max_size() << '\n';

    eastl::fixed_vector<int, 10, false> fv;
    std::cout << "size=" << fv.size() << " capacity=" << fv.capacity() << '\n';

    return 0;
}

Output:

size=0 capacity=10
size=10 capacity=10
size=0 capacity=10

Note that the size of array is 10, whereas vector and fixed_vector are 0

Steve Lorimer
  • 24,805
  • 15
  • 109
  • 200
13

Use std::array

For better readability you can make typedef:

typedef std::array<int, 10> MyIntArray;
Filip Roséen - refp
  • 60,448
  • 19
  • 148
  • 192
Andrew
  • 23,640
  • 12
  • 59
  • 90
12

This is an old question but if someone just needs constant-size indexed container with size defined at runtime, I like to use unique_ptr:

// c++14
auto constantContainer = std::make_unique<YourType []> ( size );

// c++11
std::unique_ptr<YourType[]> constantContainer {new YourType[ size ]};


// Access
constantContainer[ i ]
Pari
  • 389
  • 2
  • 5
  • 14
10

A std::vector is a dynamic container, there is no mechanism to restrict its growth. To allocate an initial size:

std::vector<int> v(10);

C++11 has a std::array that would be more appropriate:

std::array<int, 10> my_array;

If your compiler does not support C++11 consider using boost::array:

boost::array<int, 10> my_array;
hmjd
  • 117,013
  • 19
  • 199
  • 247
2

This ----> std::vector<10, int> is invalid and causes error. But the new C++ standard has introduced a new class; the std::array. You can declare an array like this:

std::array<int, 5> arr; // declares a new array that holds 5 ints
std::array<int, 5> arr2(arr); // arr2 is equal to arr
std::array<int, 5> arr3 = {1, 2, 3, 4, 5}; // arr3 holds 1, 2, 3, 4, 5

The std::array has constant size and supports iterator/const_iterator/reverse_iterator/const_reverse_iterator. You can find more about this class at http://cplusplus.com/reference/stl/array/.

Rontogiannis Aristofanis
  • 8,583
  • 8
  • 40
  • 58