Introduction To valarray

valarray is std:: vector’s  unpopular nerdy little brother.  It was designed for multi-dimensional numeric calculations.  While it may sound like a niche tool for scientific applications, It actually can be useful in other kinds of software.

Consider a vector representing a shopping list items prices,  and another vector representing the discount for each item:

#include <iostream>
#include <vector>
#include <string>
#include <sstream>

template <typename C>
std::string  seqTostring(C c)
{
    std::stringstream ss;
    ss << '(';
    for (auto it = std::begin(c); it != std::end(c); it++)
    {
        ss << *it;
        if (std::next(it) != end(c)) ss << ",";
    }
    ss << ')';
    return ss.str();
}

void calculatePrice()
{
    std::vector<double> itemPrice{ 11 , 44, 5.2, 1.99 };
    std::vector<double> itemDiscount{0 , 0.2, 0.4, 0 };
    std::vector<double> finalPrice(itemPrice.size());

    for (size_t i = 0; i < itemPrice.size(); i++)
    {
        finalPrice[i] = itemPrice[i] * (1.0 - itemDiscount[i]);
    }
    std::cout << "List of final prices: " << seqTostring(finalPrice) << '\n';
}

int main()
{
    calculatePrice();
    return 0;
}

List of final prices: (11,35.2,3.12,1.99)

Doing the same calculation with  valarray  is as straightforward as can be:


#include <valarray>
void calculatePrice()
{
   std::valarray<double> itemPrice{ 11 , 44, 5.2, 1.99 };
   std::valarray<double> itemDiscount{0 , 0.2, 0.4, 0 };
   std::valarray<double> finalPrice = itemPrice * (1.0 - itemDiscount);
   std::cout << "List of final prices: " << seqTostring(finalPrice) << '\n';
}

List of final prices: (11,35.2,3.12,1.99}

Notice how each of the elements in the itemDiscount array is individually subtracted from 1.0 before being multiplied by the corresponding element in the itemPrice array. In addition to producing a loop-free code, valarray numeric specialization allows compilers to emit highly optimized machine code under the assumption the elements in valarray are usually processed as numerical values.

For primitive numerical values such as int and double,  valarray supports, out of the box, any  type of arithmetic and logical operation:

int main()
{
 	std::valarray<unsigned int> values{ 1 /*1000*/, 13 /*1101*/ , 8 /*0001 */ };
	std::valarray<unsigned int> andResult = 8U & values;
	std::cout << "Logical AND of " << seqTostring(values) << " with 0001b : "
		<< seqTostring(andResult) << '\n';
	return 0;
}

Logical AND of (1,13,8) with 0001b : (0,8,8)

In addition, some mathematical functions, such as tan and sqrt,  are overloaded to accept a valarry:


int main()
{
	std::valarray<int> vals{ 144 , 16, 4, 81 };
	std::cout << "sqrt of  " << seqTostring(vals) << " = " << seqTostring(sqrt(vals)) << '\n';
	return 0;
}

sqrt of  (144,16,4,81) = (12,4,2,9)

However, if the function you need is not included in the standard library   you can define your own operation with the apply() method:

int main()
{
	std::valarray<int> vals{ 97,54,84,76 };
	std::valarray<int> applyResult = vals.apply([](int val)	{
		auto s = std::to_string(val);
		return std::stoi(s + s);});
	std::cout << seqTostring(vals) << " converted to " << seqTostring(applyResult) << '\n';
}

Contrary to what you would expect, apply accepts a lambda but will not accept a function object! this is the first hint of the somewhat skewed way valarray integrates with the rest of the C++ standard library.  It appears as if valarry started on a different evolutionary branch, apart from the rest of the library.  Methods such as begin(), end(),  clear()    we have gotten used to finding in a container class are missing.   If you wish to add more elements than the array capacity you must call valarray‘s  resize()  member manually with the new size  (invalidating all contained elements as a side effect )  than re-insert all old elements and add new elements  (a sort of manual reallocation).  It also means calling resize(0) effectively clear the array.

An empty valarry cause undefined behavior in simple workflows such as trying to call sum().  So you should be extra careful when working with empty arrays.
Another peculiarity of valarray implementation is an occasional compiler’s  failure to cast correctly returned types when valarrys are involved.  rewriting the previous apply() example as below compile’s fine in Visual Studio 2015, but not in GCC 4.9.2 :

int main()
{
	std::valarray<int> vals{ 97,54,84,76 };
	std::cout << seqTostring(vals) << " converted to " <<
		seqTostring(vals.apply(doubleTheNumbers)) << '\n';
}

Getting this and other instances of code involving valarrays require liberal use of static_cast<varlarry>  in order to point the compiler in the right direction.

C++ 11  took a few steps to bridge the gap,  among several updates: valarray got its own overload for the begin()/end() functions allowing it play better with the STL containers and algorithms:

std::valarray<int> vals = { 54,94,82,52,3,91,57,37,77,38 };
	std::sort(begin(vals), end(vals));
	std::cout << " sorted array: " << seqTostring(vals) << '\n';

(97,54,84,76) converted to (9797,5454,8484,7676)

Instantiating valarray with a user types  T  works in a similar way to other containers. The standart requires that constructing T with a copy constructor must be the same as instantiating T with a default constructor and using the assignment operator to assign it.  For example,  given:


struct valType
{
	int i;
	int j;
};

than

struct valType
{
	int i;
	int j;
};

valType val1{ I1,I2 }; 
valType  val2;
val2 = val1;

valType val3(val1);
assert (val2 == val3); // never fails for any I1, I2

For the full list of requirements of T see  C++ 11 standard, ISO/IEC 14882:2011(E)  section 26.2

Once you do come up with the proper type,  you will have to overload any functions you might need:

std::ostream& operator<<(std::ostream& os, const valType& vt)
{
	os << '{' << vt.i << ',' << vt.j << '}';
	return os;
}

valType sqrt(valType vt)
{
	valType res;
	res.i = sqrt(vt.i);
	res.j = sqrt(vt.j);
	return res;
}

int main()
{
	std::valarray<valType> vals{ { 4,4 },{ 16,9 },{ 256,1 },{ 1,64 } };
	std::valarray<valType> vals_sqrt = sqrt(vals);
	std::cout << seqTostring(vals) << " sqrt: " << seqTostring(vals_sqrt) << '\n';
	std::cout << seqTostring(vals) << " sum:  " << vals.sum() << '\n';
}

({4,4},{16,9},{256,1},{1,64}) sqrt: ({2,2},{4,3},{16,1},{1,8})
({4,4},{16,9},{256,1},{1,64}) sum: {277,78}

In spite of valarray’s quirks,  it can be a powerful tool when  applied with care.

In the next post, I’ll discuss the valarray [] operator, it is overloaded with som much functionality it warrants its own post.

for further reading see cppreference.com   and chapter 26.6 of the C++ 11 standard = ISO/IEC 14882:2011(E)

 

 

Why Do We Need std::addressof, If We Already Have The & Operator?

At first glance, the std::addressof method appears to be redundant. Its  output is the address of the object passed to it. It’s exactly what the & operator have been doing ever since C was developed in the early 70’s:

#include <iostream>
#include <memory>

template<typename T>
void getAddress(T t)
{
	assert( std::addressof(t) == &t);
	std::cout << "Address returned by & operator: " << std::ios::hex << &t << "\n";
	std::cout << "Address returned by addressof: " << std::ios::hex << std::addressof(t) << "\n";
}

int main()
{
	int i = 0;
	std::cout << "Getting the address of an int type \n";
	getAddress(i);
}

Getting the address of an int type:
Address returned by & operator: 20480024FC1C
Address returned by addressof: 20480024FC1C

C , however, don’t  allow operator overloading while C++ do. More specifically C++ will let you overload the & operator.  Consider instantiating the getAddress template function with the  Buffer class defined below:

#include <iostream>
#include <memory>

class Buffer
{
private:
	static const size_t buffer_size = 256;
	int bufferId;
	char buffer[buffer_size];

public:
	Buffer(int bufferId_) : bufferId(bufferId_) {}
	Buffer* operator&() { return reinterpret_cast<Buffer*> (&buffer); }  //BAD practice, only for  illustration!
};

template<typename T>
void getAddress(T t)
{
	std::cout << "Address returned by & operator: " << std::ios::hex << &t << "\n";
	std::cout << "Address returned by addressof: " << std::ios::hex << std::addressof(t) << "\n";
}

int main()
{
	Buffer b(1);
	std::cout << "Getting the address of a Buffer type: \n";
	getAddress(b);
}

Getting the address of a Buffer type:
Address returned by & operator: 20480078F50C
Address returned by addressof: 20480078F508

In the Buffer class, the & operator is (badly) overloaded and coerced to return the address of the internal  buffer as the address of the  object. The template implementation expecting a type with an accessible & operator which, it assumes,  returns the address of the object, report the wrong address.  At the same time std::addressof method returns accurately the object’s  address.

So this is why we need std::addressof. It  was introduced into  the boost library and later into the C++ 11 standard as a workaround for a potentially unreliable & operator.

When should you use the std::addressof  method?

You should use std::addressof instead of & in any template implementation taking the address of a user-defined object. Doing so is not a perfect solution as it might  cause unexpected  behavior with types relying on an overloaded & operator (some argue it is an appropriate and just  punishment for developers dabbling in this dark art) .  However, it is possible to  detect the conflict of address reporting and  template expectations in debug builds  with assert( std::addressof(t) == &t) :

template<typename T>
void getAddress(T t)
{
	assert( std::addressof(t) == &t);
	std::cout << "Address returned by & operator: " << std::ios::hex << &t << "\n";
	std::cout << "Address returned by addressof: " << std::ios::hex << std::addressof(t) << "\n";
}

This way you will at least get a heads up while you develop and test your code.

Conclusion

Even prior to C++11 ,  Overloading the & operator has been discouraged, frowned upon  and even prohibited by several C++ coding guidelines such as the one used in aircraft and medical devices software development:   MISRA-C++:2008  (section 5-3-3).  A boost library version of addressof was released in  2002 suggesting that overloading the address operator was perceived as a problem for a long while before the C++ 11 makeover. Yet, the  introduction of the std::addressof  method  into the C++11  standard  is evidence that  the C++ committee  feared too much legacy code will break if the & operator no longer allowed to be overloaded.  I guess this is one case where the jokes about C++ giving you the tools to shoot yourself in the foot are right on the nose.