Search

1.4 — Variable assignment and initialization

In the previous lesson (1.3 -- Introduction to objects and variables), we covered how to define a variable that we can use to store values. In this lesson, we’ll explore how to actually put values into variables and use those values.

As a reminder, here’s a short snippet that first allocates a single integer variable named x, then allocates two more integer variables named y and z:

Variable assignment

After a variable has been defined, you can give it a value (in a separate statement) using the = operator. This process is called copy assignment (or just assignment) for short.

Copy assignment is named such because it copies the value on the right-hand side of the = operator to the variable on the left-hand side of the operator. The = operator is called the assignment operator.

Here’s an example where we use assignment twice:

When we assign value 7 to variable width, the value 5 that was there previously is overwritten. Normal variables can only hold one value at a time.

Warning

One of the most common mistakes that new programmers make is to confuse the assignment operator (=) with the equality operator (==). Assignment (=) is used to assign a value to a variable. Equality (==) is used to test whether two operands are equal in value.

Initialization

One downside of assignment is that it requires at least two statements: one to define the variable, and one to assign the value.

These two steps can be combined. When a variable is defined, you can also provide an initial value for the variable at the same time. This is called initialization. The value used to initialize a variable is called an initializer.

Initialization in C++ is surprisingly complex, so we’ll present a simplified view here.

There are 4 basic ways to initialize variables in C++:

We’ll cover the case of what happens when no initializer is provided in the next lesson (1.6 -- Uninitialized variables and undefined behavior).

You may see the above forms written with different spacing (e.g. int d{7};). Whether you use extra spaces for readability or not is a matter of personal preference.

Copy initialization

When an initializer is provided after an equals sign, this is called copy initialization. Copy initialization was inherited from the C language.

Much like copy assignment, this copies the value on the right-hand side of the equals to the variable being created on the left-hand side.

For simple types like int, copy initialization is efficient. However, when types get more complex, copy initialization can be inefficient.

Direct initialization

When an initializer is provided inside parenthesis, this is called direct initialization.

For simple data types (like int), copy and direct initialization are essentially the same. For more complicated types, direct initialization tends to be more efficient than copy initialization.

List initialization

Unfortunately, direct initialization can’t be used for all types of initialization (such as initializing an object with a list of data). To provide a more consistent initialization mechanism, there’s list initialization (also sometimes called uniform initialization or brace initialization) that uses curly braces.

List initialization comes in three forms:

Direct and copy list initialization function almost identically, but the direct form is generally preferred.

List initialization has the added benefit of disallowing “narrowing” conversions. This means that if you try to use list initialization to initialize a variable with a value it can not safely hold, the compiler will throw a warning or an error. For example:

In the above snippet, we’re trying to assign a number (4.5) that has a fractional part (the .5 part) to an integer variable (which can only hold numbers without fractional parts). Copy and direct initialization would drop the fractional part, resulting in initialization of value 4 into variable width. However, with list initialization, this will cause the compiler to issue an error (which is generally a good thing, because losing data is rarely desired). Conversions that can be done without potential data loss are allowed.

Best practice

Favor initialization using braces whenever possible.

Q: C++ provides copy, direct, and list initialization, and copy assignment. Is there a direct or list assignment?

No, C++ does not support a direct or list assignment syntax.

Value initialization and zero initialization

When a variable is initialized with empty braces, value initialization takes place. In most cases, value initialization will initialize the variable to zero (or empty, if that’s more appropriate for a given type). In such cases where zeroing occurs, this is called zero initialization.

Q: When should I initialize with { 0 } vs {}?

Use an explicit initialization value if you’re actually using that value.

Use value initialization if the value is temporary and will be replaced.

Initialize your variables

Initialize your variables upon creation. You may eventually find cases where you want to ignore this advice for a specific reason (e.g. a performance critical section of code that uses a lot of variables), and that’s okay, as long the choice is made deliberately.

For more discussion on this topic, Bjarne Stroustrup (creator of C++) and Herb Sutter (C++ expert) make this recommendation themselves here.

We explore what happens if you try to use a variable that doesn’t have a well-defined value in lesson 1.6 -- Uninitialized variables and undefined behavior.

Best practice

Initialize your variables upon creation.

Initializing multiple variables

In the last section, we noted that it is possible to define multiple variables of the same type in a single statement by separating the names with a comma:

We also noted that best practice is to avoid this syntax altogether. However, since you may encounter other code that uses this style, it’s still useful to talk a little bit more about it, if for no other reason than to reinforce some of the reasons you should be avoiding it.

You can initialize multiple variables defined on the same line:

Unfortunately, there’s a common pitfall here that can occur when the programmer mistakenly tries to initialize both variables by using one initialization statement:

In the top statement, variable “a” will be left uninitialized, and the compiler may or may not complain. If it doesn’t, this is a great way to have your program intermittently crash and produce sporadic results. We’ll talk more about what happens if you use uninitialized variables shortly.

The best way to remember that this is wrong is to consider the case of direct initialization or list initialization:

This makes it seem a little more clear that the value 5 is only being used to initialize variable b or d, not a or c.

Quiz time

Question #1

What is the difference between initialization and assignment?

Show Solution

Question #2

What form of initialization should you be using?

Show Solution


1.5 -- Introduction to iostream: cout, cin, and endl
Index
1.3 -- Introduction to objects and variables

184 comments to 1.4 — Variable assignment and initialization

  • Thang

    I saw that most people codes c++ usually using copy assignment for create variables or constant variables, I don't why using it rather uses the recommend direct list initialization. Anyone have the answer? Please comments.

    • Charles

      It's because of these reasons "For more complicated types, direct initialization tends to be more efficient than copy initialization." is more efficient than copy initialization. "List initialization has the added benefit of disallowing “narrowing” conversions. This means that if you try to use list initialization to initialize a variable with a value it can not safely hold, the compiler will throw a warning or an error." it shows an error when something is wrong which is a good thing in case you missed something.

    • Hamish Poole

      It's probably because other languages do not make the distinction between direct and copy assignment, and only provide one tool for assignment.  

      The distinction between direct and copy initialisation is only valuable in performance critical concepts, but if you have a garbage collector for your language you probably don't care about such a detail.

      Which is var = value;

      I wonder what Rust does.

  • Austin

    @Alex I think it's worth mentioning that list initialization is supported only as of C++11. Where as if you're in a situation that has to use an older version of C++ (e.g. 98), you'll have to fallback to direct initialization.

  • Willem

    Cool, I didnt even know about direct list initialization, and I've been programming for about three years now (mainly scripting languages and a bit of C). These early chapters provide some necessary work on my foundations, thanks a ton!

  • Manuel Calzadillas

    Thanks for the lesson,
    Hope to finish soon

  • nuke

    What is the downside to not initializing a variable?

    Also, what is the difference between direct and copy initialization besides syntax? Why can direct initialization be more efficient? When is it more efficient? Are there any situations where copy initialization is preferred? On that note, does direct list initialization _not_ work for some things?

    Finally, I have a question about how the examples initialize variables:

    Is it just easier to read the first two ways? Is either one preferable over the other?

    • Alex

      Not initializing a variable leaves the variable with an indeterminate value. In the majority of cases, it won't matter because you're likely not reading the value before assigning it one, but mistakes happen and bugs of this nature can be hard to find. Put another way, what's the upside to _not_ initializing a variable? I'd argue that doing so for performance is a form of premature optimization.

      For variables of fundamental types (e.g. int) there's no difference between copy and direct initialization. For complex types (e.g. classes) copy initialization has historically involved creating temporary objects and copying them, which direct initialization does not do. However, with the compiler free to optimize and changes made in C++17 to support more optimization, the actual performance gap is likely not that large these days. The main difference today (for complex types) is what happens when a type conversion is needed to initialize the object (too complex to explain here). None of the initialization forms work for every use case, but list initialization works for the most cases and is the safest.

      C++ ignores whitespace so the difference between your 3 variable initialization is purely stylistic.

      • Glowerworm

        Hi, just wanted to tell you that this is a _fantastic_ learning site. Everything is explained so fluently and elegantly, you all should absolutely be proud. Do you take donations? I am strapped for cash currently but I would like to donate a few months from now when I am capable.

  • jerron

    Is there situation that direct initialization better than list initialization? if not, why is it introduced?

    • nascardriver

      List-initialization favors list-constructors. If a type has a list- and a non-list-constructor and you want to call the non-list-constructor, you can't use list-initialization. Constructors and list-constructors are covered later.

      For the types you know now, there is no reason to use direct-initialization.

  • Manikanta

    Does
    defining two variables of same Data Type like this "int a,b{10} " makes any error?

  • alann bambara

    why is it recommended to use:
    int numb{2};
    instead of:
    int numb = 2;

    • Alex

      With integer initialization, it doesn't really matter. But as we get into initialization of other types in future lessons, we'll use {} because = either doesn't work or is less efficient. So trying to set up good, consistent habits now.

  • xNoi

    why not just use all the varibles in 1 line, it would save space
    like this

    • Alex

      This works fine for simple types like int, but becomes more error prone for more complicated types that we cover later in this tutorial series.

      Also this form becomes significantly harder to read once each variable needs an initialization value.

  • Vega

    Is there any teaching for string type variables? like string charName = "Chad";  ?

    i see there are only integer type variables in this chapter. a great tutorial nonetheless im barely moving forward into chapter 2 and was wondering why i haven't learned about string type variables yet.

  • Julian

    Why use direct list initialization all the time, what about?

    • Alex

      Direct list initialization offers the most consistency (it works for almost everything) and protection (e.g. against unintended narrowing conversions)

  • Why does int x() returns 1? It's returning 1 as True or it's the value assigned to x?

Leave a Comment

Put all code inside code tags: [code]your code here[/code]