Concepts / Copying Values into Container Storage

Copying Values into Container Storage

A container such as a vector of numbers is a common case.

  • Programming

Building a Container Already Full

Often we want an object that already holds several values the moment it is declared. A container such as a vector of numbers is a common case. The slow way is to create an empty object and then add each element one at a time. C++ offers a shorter way: write the values directly, inside braces, and let the object be built from them. The mechanism that makes this possible is a special kind of constructor called an initializer-list constructor.

In this article we will follow one braced list from the moment it is written to the moment the finished object exists. The running example is a class named Vector, whose constructor accepts a list of double values. Keep the question in mind as you read: how many elements will the object hold, and how did the values get there?

From Braces to One Object

The braces are not passed to the constructor as text, and they are not handed over as a loose set of separate arguments. Instead, the list of values is packaged into a single std::initializer_list object, and that one object is what the constructor receives. The compiler performs this packaging whenever a braced list is used, so the same mechanism applies to any list of values written in braces, as long as the class provides a suitable constructor.

Braced list1, 2, 3, 4, 5std::initializer_listone packaged objectVector constructorreceives the listVector's own storage5 double valuespackaged by compilerpassed as the argumentcopies each value
What happens first, next, and last when the compiler sees a braced list and builds a Vector from it, and how the values end up stored in the object.

Read the diagram from top to bottom. The braced list becomes one std::initializer_list object before the constructor runs. The constructor then copies values from that object into storage belonging to the Vector. The number of values inside the braces determines how many elements the object holds, because the element count comes from the same list.

What std::initializer_list Holds

Definition

std::initializer_list is the type of the single object that the compiler creates from a braced list. The constructor receives this object as its argument. It gives the constructor access to the values written in the braces and to how many of them there are.

The key point is that std::initializer_list is a way of handing over the list, not a container that the object keeps. The list is read once. Its values are used as a source, and the object keeps its own copy of those values in its own memory. The picture below shows the list as a view over a group of values, with the cells holding the values in order.

initializer_listthe handed-over listvalues from thebracesgroup of 5 valuesvalue 01.0value 12.0value 23.0value 34.0value 45.0refers tocontainscontainscontainscontainscontains
The initializer_list object refers to a group of values written in the braces. The constructor reads these values in order and copies them into the object's own storage.

Writing the Constructor Signature

An initializer-list constructor is recognized by its parameter. Its argument has the type std::initializer_list followed by the type of the values it holds. In the Vector class, the constructor takes a list of double values, so the parameter type is std::initializer_list<double>. The declaration below is the form used in the source.

cpp
Notes on the code
  • Vector:: names the class whose constructor is being defined
  • std::initializer_list<double> is the argument type, one packaged object holding the braced values
  • lst is the name the constructor uses to read the values

Once the constructor has the list, it must give the object its own storage and fill it. The member initializers allocate a new array of doubles sized by the list, and the element count is recorded by converting the list's size to an int. The body then copies every value from the list into the newly allocated storage. A simplified sketch of that shape is shown below. The copy loop is an illustration of the copying step described in the source, not a complete class.

cpp
Notes on the code
  • elem gets a new array sized by the number of values in the list
  • sz records the element count, converted from the list's size to an int
  • the loop copies each value from the list into the object's own storage

Tracing the Copy Step by Step

What do you think happens?

Given a Vector constructed from the braced list {1,2,3,4,5}, how many elements does the finished object hold?

  • 0

  • 1

  • 5

Reveal answer
Answer:

5

The number of elements in the constructed object equals the number of values written inside the braces. The five values in the list give five elements.

Worked example

Following the braced list {1,2,3,4,5} into a Vector

A Vector with an initializer-list constructor is declared with the braced list {1,2,3,4,5}. Trace how the values reach the object.

  1. 1
    Step 1: the compiler packages the list

    The braces are turned into one std::initializer_list object holding the five values. The braces themselves are not passed along as separate arguments.

  2. 2
    Step 2: the constructor receives the object

    The initializer-list constructor takes std::initializer_list<double> as its argument, so the packaged object is the value it gets.

  3. 3
    Step 3: the storage is sized

    The member initializers allocate an array of doubles sized by the list. The element count is set to the list's size, which is 5.

  4. 4
    Step 4: the values are copied

    The body copies each value from the list into the new array. The object keeps its own copy, so it does not depend on the list after the copy is made.

Result

The Vector holds five elements, 1, 2, 3, 4, and 5, stored in its own memory.

Mistakes with Brace-List Initialization

  • Common mistake

    Thinking the braces are passed to the constructor as separate arguments

    Why it fails

    The source states the list is packaged into a single std::initializer_list object, and that one object is what the constructor receives.

    Do this instead

    Think of the braced list as one object carrying all the values, and give the constructor a single parameter of type std::initializer_list.

  • Common mistake

    Assuming the object keeps a reference to the braced values

    Why it fails

    The constructor reads the list and copies the values into the object's own storage. The object holds its own copy.

    Do this instead

    Expect the object's elements to be its own copies, stored in memory the object owns.

  • Common mistake

    Expecting the element count to be set separately from the list

    Why it fails

    The element count of the constructed object equals the number of values written inside the braces.

    Do this instead

    Count the values inside the braces to know how many elements the object will hold.

  • Common mistake

    Treating braces and parentheses as interchangeable when a class has an initializer-list constructor

Practice: Counting and Tracing Values

EASY

A Vector is declared with the braced list {10, 20, 30}. Without running any code, state how many elements the object holds, and describe in order which object the constructor receives and where the values are copied.

Hints
  • Count the values written inside the braces.
  • Recall that the braces are packaged into one std::initializer_list object before the constructor runs.

Key Takeaways

  • A braced list such as {1,2,3,4,5} is packaged by the compiler into one std::initializer_list object, and that object is what the constructor receives.
  • An initializer-list constructor takes std::initializer_list<T> as its argument, as in Vector::Vector(std::initializer_list<double> lst).
  • The constructor sizes its storage from the list and copies each value into the object's own elem storage, so the object does not depend on the list afterward.
  • The number of elements in the constructed object equals the number of values written inside the braces.

Related concepts

More concepts starting with C