C++ Valarray VS. Vector

C++ valarray vs. vector

Valarrays (value arrays) are intended to bring some of the speed of Fortran to C++. You wouldn't make a valarray of pointers so the compiler can make assumptions about the code and optimise it better. (The main reason that Fortran is so fast is that there is no pointer type so there can be no pointer aliasing.)

Valarrays also have classes which allow you to slice them up in a reasonably easy way although that part of the standard could use a bit more work. Resizing them is destructive and they lack iterators they have iterators since C++11.

So, if it's numbers you are working with and convenience isn't all that important use valarrays. Otherwise, vectors are just a lot more convenient.

What is the difference between std::valarray and std::array

  • valarray was already in C++03, array is new in C++11
  • valarray is variable length, array is not.
  • valarray is designed for numeric computations and provides plenty of operations including +, -, *, cos, sin, etc... array does not.
  • valarray has an interface to retrieve slices of the array (sub arrays), array does not.

valarray vs. vector: Why was valarray introduced?

Separation of concern? A vector and a valarray solve different problems. Quoting from the standard, a vector is a (§23.3.6.1 [vector.overview] p1)

... sequence container that supports random access iterators. In addition, it supports (amortized) constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage management is handled automatically, though hints can be given to improve efficiency.

while a valarray is a (§26.6.2.1 [template.valarray.overview] p1)

... one-dimensional smart array, with elements numbered sequentially from zero. It is a representation of the mathematical concept of an ordered set of values. The illusion of higher dimensionality may be produced by the familiar idiom of computed indices, together with the powerful subsetting capabilities provided by the generalized subscript operators.

As you can see, they serve different purposes. A vector is a generalized dynamic array, while a valarray represents a set of values. It's also not resizeable and only assignable.

Why are std::vector and std::valarray initializing constructors different?

Because they don't come from the same place: vector comes from the STL library, and valarray doesn't (I haven't been able to find out where it comes from, but there seem to be strong connections to Fortran).

Quoting Bjarne himself:

Most of the time, work on each of these components progressed in
isolation from work on the others. There was no overall design or
design philosophy.

[...]

Basically, the committee failed to contain “design by committee” so
whereas the STL reflects a clear philosophy and coherent style, most
of the other components suffered. Each represents its own style and
philosophy, and some (such as string) manage simultaneously to present several.

(From "Evolving a language in and for the real world: C++ 1991-2006".)

So I would say that the rationale is the traditional C++ one, "things are the way they are, and changing them for the sake of Standardization would break a lot of things, so let's leave well enough alone".

How to pass a vector or a valarray as an argument to a C++ template function

std::vector has 2 template parameters. The second one is the allocator, which has a default value so you normally don't use it.

However, prior to c++17 template template parameters would only match if the number of template arguments where the same. In c++17 this was relaxed a bit and it's since allowed to match a template with more template parameters as long as the remaining ones have default arguments.

Regardless of this, I would propose a solution that uses the member type in both containers, value_type.

#include <vector>
#include <algorithm>
#include <valarray>

template <class T>
auto GetPercentile(T& vData, double dPercentile)
{
using elType = typename T::value_type;
int iOffset = int(dPercentile * vData.size());
std::nth_element(begin(vData), begin(vData) + iOffset, end(vData));
return static_cast<elType>(vData[iOffset]);
}

int main() {
auto v = std::vector<int>{1,2,3,4,5};
GetPercentile(v, 2);

auto a = std::valarray<int>(5, 5);
GetPercentile(a, 2);
}

Assign a std::vector to a std::valarray

To create a valarray from a vector:

std::valarray<double> corpX(corps_tmp[i].data(), corps_tmp[i].size());

To write the data back into a vector:

corps_tmp[i].assign(std::begin(corpX), std::end(corpX));


Related Topics



Leave a reply



Submit