Correct way to work with vector of arrays
Asked Answered
M

5

86

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?

Messalina answered 6/1, 2011 at 6:11 Comment(1)
You can't have a vector of native arrays, because they are neither assignable nor copyable.Redletter
I
160

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.)

Idette answered 6/1, 2011 at 6:18 Comment(5)
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, at least with the default allocator.Jolty
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?".Manson
ideone.com/ENLC68 ?Diffuser
Actually one can store arrays in vectors now, see https://mcmap.net/q/243660/-using-c-style-arrays-in-std-vector-msvc-bugCini
How do you push_back a literal to this vector?Incredible
C
12

Use:

vector<vector<float>> vecArray; //both dimensions are open!
Caresa answered 6/1, 2011 at 6:15 Comment(1)
vector of vector is not contiguous, in case that is required by the OP.Parttime
J
12

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.

Jijib answered 6/10, 2014 at 11:37 Comment(3)
In your example arr is being dangerously cast to a pointer. If arr goes out of scope while vec still exists an undefined behavior (likely stack overflow) will occur.Spaghetti
this just made the vector non-copyable.Glutenous
You cannot return this vector. Because the pointer will be released. So, the pointer vector is useless.Goodish
R
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);
Roxi answered 6/1, 2011 at 6:17 Comment(1)
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 typeSuzan
E
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.

Eulogize answered 25/2, 2023 at 11:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.