85

Could someone tell what is the correct way to work with a vector of arrays?

I declared a vector of arrays (vector<float[4]>) but got error: conversion from 'int' to non-scalar type 'float [4]' requested when trying to resize it. What is going wrong?

Pulkit Sinha
  • 2,654
  • 4
  • 19
  • 20

5 Answers5

157

You cannot store arrays in a vector or any other container. The type of the elements to be stored in a container (called the container's value type) must be both copy constructible and assignable. Arrays are neither.

You can, however, use an array class template, like the one provided by Boost, TR1, and C++0x:

std::vector<std::array<double, 4> >

(You'll want to replace std::array with std::tr1::array to use the template included in C++ TR1, or boost::array to use the template from the Boost libraries. Alternatively, you can write your own; it's quite straightforward.)

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 8
    The second sentence is no longer true in C++11, but the rest is still correct. The problem in C++11 is that arrays are not [`Erasable`](http://en.cppreference.com/w/cpp/concept/Erasable), at least with the default allocator. – T.C. Jan 12 '16 at 03:22
  • 1
    For requirements on STL containers(post C++11), take a look at this thread, ["Has C++11 changed requirements for elements of STL containers, and how?".](https://stackoverflow.com/questions/13577881/has-c11-changed-requirements-for-elements-of-stl-containers-and-how) – MaxPlankton Mar 18 '18 at 10:45
  • https://ideone.com/ENLC68 ? – Jason C Apr 21 '22 at 04:03
  • Actually one can store arrays in vectors now, see https://stackoverflow.com/a/75561253/7325599 – Fedor Feb 25 '23 at 09:55
11

There is no error in the following piece of code:

float arr[4];
arr[0] = 6.28;
arr[1] = 2.50;
arr[2] = 9.73;
arr[3] = 4.364;
std::vector<float*> vec = std::vector<float*>();
vec.push_back(arr);
float* ptr = vec.front();
for (int i = 0; i < 3; i++)
    printf("%g\n", ptr[i]);

OUTPUT IS:

6.28

2.5

9.73

4.364

IN CONCLUSION:

std::vector<double*>

is another possibility apart from

std::vector<std::array<double, 4>>

that James McNellis suggested.

11

Use:

vector<vector<float>> vecArray; //both dimensions are open!
Nawaz
  • 353,942
  • 115
  • 666
  • 851
4

Every element of your vector is a float[4], so when you resize every element needs to default initialized from a float[4]. I take it you tried to initialize with an int value like 0?

Try:

static float zeros[4] = {0.0, 0.0, 0.0, 0.0};
myvector.resize(newsize, zeros);
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • This (after obvious minor fixes) doesn't compile, for the same reason as given in the accepted answer: it's not valid because plain arrays aren't valid container element types. 1st error from `g++`: `C:/msys64/mingw64/include/c++/10.2.0/bits/stl_uninitialized.h:281:63: error: static assertion failed: result type must be constructible from input type` – underscore_d May 28 '21 at 08:26
1

Since C++11 the only general requirement on the element of a vector is that it satisfies the Erasable requirement with the used allocator. It basically requires that the object type can be destroyed through a properly rebound std::allocator_traits::destroy.

With the standard allocator std::allocator, this requirement was not satisfied before C++20, because std::allocator::destroy would try to use a simple (pseudo-)destructor call which is well-formed only for class and scalar types, not for array types.

Since C++20 std::allocator's destroy is defaulted through std::allocator_traits to use std::destroy_at and std::destroy_at is extended to support array types by calling itself recursively on the array elements. So the Erasable requirement is now fulfilled with array types and it is not generally forbidden to use array types in std::vector with the default allocator anymore.

However, when actually constructing elements in the vector, the vector must use the allocator's construct, which was also defaulted with C++20 to use std::construct_at. Unfortunately std::construct_at doesn't work with arrays, which is probably unintentional (see open LWG issue 3436). So currently it is not possible to construct any elements in such a vector with the default allocator and the only way to use std::vector<float[4]> is to construct an empty instance.

Even when this issue is resolved, there is however almost no use for such a vector. The only thing one can do with it is constructing an instance with a given number of value-initialized elements and then operate on this fixed-size vector's elements. None of the modifiers can be used because they require some form of copying or moving of the element type, which isn't possible for array types. Such a vector can be moved and swapped, but not copied.

user17732522
  • 53,019
  • 2
  • 56
  • 105