Filling <algorithm>s of the STL
This post is part of the STL learning resource. Today we focus on how to fill out a range or a container with the STL.
std::fill and std::uninitialized_fill
std::fill takes a range and a value, and sets all elements of the range as equal to this value.
vector<int> v = {1, 2, 3, 4, 5};
fill(v.begin(), v.end(), 3);
// v contains {3, 3, 3, 3, 3};
std::fill calls operator= on each element.
std::uninitialized_fill does essentially the same thing, but it takes a range of memory that has been allocated but not initialized (for instance with operator new, malloc, or a custom memory allocator).
This algorithm performs the initialization of each element with the passed value, which means that it calls its constructor taking a value of this type. So std::uninitialized_fill does not call operator=.
The following example illustrates how std::uninitialized_fill can be used:
class MyClass
{
public:
explicit MyClass(int i);
private:
int i_;
};
// Allocate a buffer that can contain 5 objects of MyClass
MyClass* myObjects = static_cast<MyClass*>(malloc(5 * sizeof(MyClass)));
// Call constructor on each object, with value 3
std::uninitialized_fill(myObjects, myObjects + 5, 3);
// Use myObjects...
// Call destructor on each object
std::for_each(myObjects, myObjects + 5, [](const MyClass& object){object.~MyClass();});
// Deallocate the buffer
free(myObjects);
myObjects = nullptr;
This is conceptually very similar to an placement new in an array, but without the drawbacks associated to the unknown size allocated in arrays by the compiler for bookkeeping.
std::generate and std::iota
std::generate takes a range and a function (or function object) callable with no parameter, and assigns to each element of the range the value returned by a call to the function.
Its canonical example of usage is filling a range with random values :
int getRandomNumber();
vector<int> v = {1, 2, 3, 4, 5};
generate(v.begin(), v.end(), getRandomNumber);
// v may contain {7, 257, -3, 18, -44};
And std::iota fills a range with incremental values obtained with prefix operator++, starting from a given value:
vector<int> = {1, 2, 3, 4, 5};
iota(v.begin(), v.end(), 10);
// v now contains {10, 11, 12, 13, 14}
*_n algorithms
std::fill, std::uninitialized_fill and std::generate have *_n couterparts, namely std::fill_n, std::uninitialized_n and std::generate_n, that take an output iterator, along with a size.
template <typename OutputIterator, class Size, class T> OutputIterator fill_n(OutputIterator first, Size count, const T& value);
These algorithms are useful if you need to fill the first n elements of your collection:
std::vector<char> v = {'h', 'e', 'l', 'l', 'o', '!'};
std::fill_n(begin(v), 3, 'a');
// v contains {'a', 'a', 'a', 'l', 'o', '!'};
They can also be used to append several identical values to a collection. For instance std::generate_n can typically be used to fill out a empty collection with random numbers:
int randomNumberGenerator()
{
static std::random_device random_device;
static std::mt19937 engine{random_device()};
static std::uniform_int_distribution<> distribution(1,6);
return distribution(engine);
}
std::vector<int> numbers;
std::generate_n(std::back_inserter(numbers), 10, randomNumberGenerator);
// numbers may now contain {4, 1, 1, 6, 6, 3, 2, 5, 4, 1}
(In this particular case, we could have reserved the allocated size for 10 elements, but let’s focus on the algorithm here.)
A similar technique was used in the Pi Day challenge for the most expressive code.
Containers methods
vector, deque, list and string have methods that can fill them with values: their constructor, and their assign method.
The constructor can be used that way:
vector<string> v(3, "hello");
// vector now contains {“hello”, “hello”, “hello”},
(or more accurately, it contains strings representing these characters)
Here, the vector constructs one string from the passed value (“hello”), and then creates the other elements by copy-constructing from that string
The assign method constructs one object from the passed value, then calls operator= on each element to assign it with this constructed object:
vector<string> v;
v.assign(3, “hello”);
// vector now contains {“hello”, “hello”, “hello”},
(or more accurately, it contains strings representing these characters)
For more about STL algorithms, have a look at the STL learning resource.
Don't want to miss out ? Follow:   Share this post!

