Does the simpler interface that valarray provides translate to better performance? In most cases, no. The simple notation is typically implemented with the same sort of loops you would use with ordinary arrays. However, some hardware designs allow vector operations in which the values in an array are loaded simultaneous into an array of registers and then processed simultaneously. In principle, valarray operations could be implemented to take advantage of such designs.
Can you use the STL with valarray objects? Answering this question provides a quick review of some STL principles. Suppose you have a valarray
valarray
After the array has been filled with numbers, can you, say, use the STL sort function on it? The valarray class doesn’t have begin() and end() methods, so you can’t use them as the range arguments:
sort(vad.begin(), vad.end()); // NO, no begin(), end()
Also vad is an object, not a pointer, so you can’t imitate ordinary array usage and provide vad and vad + 10, as the following code attempts to do:
sort(vad, vad + 10); // NO, vad an object, not an address
You can use the address operator:
sort(&vad[0], &vad[10]); // maybe?
But the behavior of using a subscript one past the end is undefined for valarray. This doesn’t necessarily mean using &vad[10] won’t work.(In fact, it did work for all six compilers used to test this code.) But it does mean that it might not work. For the code to fail, you probably would need a very unlikely circumstance, such as the array being butted against the end of the block of memory set aside for the heap. But, if a $385-million mission depended on your code, you might not want to risk that failure.
C++11 remedies the situation by providing begin() and end() template functions that take a valarray object as an argument. So you would use begin(vad) instead of vad.begin(). These functions return values that are compatible with STL range requirements:
sort(begin(vad), end(vad)); // C++11 fix!
Listing 16.20 illustrates some of the relative strengths of the vector and valarray classes. It uses push_back() and the automatic sizing feature of vector to collect data. Then after sorting the numbers, the program copies them from the vector object to a valarray object of the same size and does a few math operations.
Listing 16.20. valvect.cpp
// valvect.cpp -- comparing vector and valarray
#include
#include
#include
#include
int main()
{
using namespace std;
vector
double temp;
cout << "Enter numbers (<=0 to quit):\n";
while (cin >> temp && temp > 0)
data.push_back(temp);
sort(data.begin(), data.end());
int size = data.size();
valarray
int i;
for (i = 0; i < size; i++)
numbers[i] = data[i];
valarray
sq_rts = sqrt(numbers);
valarray
results = numbers + 2.0 * sq_rts;
cout.setf(ios_base::fixed);
cout.precision(4);
for (i = 0; i < size; i++)
{
cout.width(8);
cout << numbers[i] << ": ";
cout.width(8);
cout << results[i] << endl;
}
cout << "done\n";
return 0;
}
Here is a sample run of the program in Listing 16.20:
Enter numbers (<=0 to quit):
3.3 1.8 5.2 10 14.4 21.6 26.9 0
1.8000: 4.4833
3.3000: 6.9332
5.2000: 9.7607
10.0000: 16.3246
14.4000: 21.9895
21.6000: 30.8952
26.9000: 37.2730
done
The valarray class has many features besides the ones discussed so far. For example, if numbers is a valarray
valarray
There are extended versions of subscripting. Let’s look at one—the slice class. A slice class object can be used as an array index, in which case it represents, in general, not just one value but a subset of values. A slice object is initialized to three integer values: the
varint[slice(1,4,3)] = 10; // set selected elements to 10