Search

1.4 — Variable assignment and initialization

In the previous lesson (1.3 -- Introduction to 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 the 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.

Copy and direct 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.

C++ supports three basic ways to initialize a variable. First, we can do copy initialization by using an equals sign:

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.

Second, we can do a direct initialization by using parenthesis.

For simple data types (like integers), copy and direct initialization are essentially the same. But for some advanced types, direct initialization can perform better than copy initialization. Prior to C++11, direct initialization was recommended over copy initialization in most cases because of the performance boost.

Uniform initialization in C++11

Unfortunately, direct initialization can’t be used for all types of initialization. In an attempt to provide a more consistent initialization mechanism, C++11 added a new syntax for direct initialization called brace initialization (also called uniform initialization) that uses curly braces:

Initializing a variable with empty braces indicates zero initialization. Zero initialization generally initializes the variable to zero (or empty, if that’s more appropriate for a given type).

Uniform initialization has the added benefit of disallowing “narrowing” conversions. This means that if you try to use uniform initialization to initialize a variable with a value it can not safely hold, the compiler will throw an warning or 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 uniform initialization, this will cause the compiler to issue an error (which is generally a good thing, because losing data is rarely desired).

Best practice

Always 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.

Best practice

If you’re using a C++11 compatible compiler, favor uniform initialization.

Author's note

Many of the examples in this tutorial series were written before uniform initialization existed and thus still use copy or direct initialization. We’re working on getting these updated. Please forgive our lack of adherence to best practice in this regard.

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

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

In C++11, move assignment was added, but it uses the same syntax as copy assignment. We cover move assignment in the chapter on smart pointers.

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

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

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

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 uniform 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 (assume your compiler is C++11 compliant)

Show Solution


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

63 comments to 1.4 — Variable assignment and initialization

  • Question

    What's an explicit initialization?

  • Someone78

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

    "an warning" should be "a warning".

  • Amber

    Hey people
    The article says that Direct initialization can't be used for all types of initialization.

    Is there any example where uniform initialization works but not direct?

  • Mabel

    Hi Alex/Nascardriver,

    I was reading the information on
                   - Copy Variable and
                   - Initialization
    and was wondering what the main difference is between the both?
    When should I use assignment =
    When should I use initialization {}
    because they both require a variable and value to be created.

    (Main difference is that in initialization, the value is made whilst variable is being created)

  • Rylee

    Hi, you've written here

    "Above, we’re trying to assign a number that has a fractional component to an integer variable
    (that cannot hold a fractional component).

    I understand what is meant in the first sentence but the following text in the brackets () I don't understand. What does that mean? I get the fact that we are trying to assign a number that follows the integer variable functional component... yet in the brackets it say - cannot hold a functional component.

  • Mabel

    With the Variable Assignment, it says "After a variable has been defined, you can give it a value (in a separate statement) by using the = operator." Does that mean we can give whatever value we want or? If so, how will we know how much to give. Sorry I'm new at this.

    • Mabel

      This is also the same as Uniform Initialization - When a variable is defined, you can also provide an initial value for the variable at the same time. This is called initialization"
      What does it mean by initial value, same as before (Does that mean we can give whatever value we want or? If so, how will we know how much to give)

      • Alex

        Yes, it means you can provide your variable with a starting value. If you don't know how much to give, you zero initialize it.

    • The value needs to be of the same type as the variable. If that's the case, there are no restrictions.

  • Lisa

    What does Copy, direct and uniform initialization actually mean? Like what does it do? I know how to put them in Visual Studio but what does it really do? And how will I know which one to use when?

    • https://www.learncpp.com/cpp-tutorial/variable-assignment-and-initialization/comment-page-1/#comment-405238
      I think I wrote another explanation somewhere, but I can't find it.
      Use brace initialization (uniform initialization), unless you can't (because you don't want to call a list constructor).

  • Napalm

    After seeing many times in later chapters people being told to use uniform initialisation, I've come back to read the reasons why. I can imagine that many people will find it hard to change to uniform initialisation. I'm a complete beginner and I already don't like the syntax of it. It seemed more intuitive to use int a = 10. Having even more curly braces to look at is not exactly a welcome change. Not to mention that in nearly all the forums, tutorials and youtube videos I've used, they pretty much all use copy initialisation, at least at a beginner level that is.

    Hmph...

    • Alex

      The good news is that once you get into arrays and classes, the curly brace initialization feels a little more natural in that context, since you're typically initializing an object with multiple values.

  • Alireza

    HELLO,
    Every time we send a piece of code in this site, you always tell us that "use Uniform initialization".
    Why do you suggest this way to initialize variables ?
    Why don't we use Copy initialization or Direct initialization ?
    When are they useful ?
    If they're bad way, why C++ defines them to initialize variables ?

    • > Why do you suggest this way to initialize variables
      Prevents narrowing casts (eg. float to int).
      Works almost everywhere.
      Solves the most vexing parse (Variable declaration is interpreted and a function declaration).
      Can be used in return-statements without repeating the type.

      > Why don't we use Copy or Direct initialization
      It doesn't prevent narrowing casts.
      If you're using an old version of C++, it might create temporaries, which is slow (Copy initialization only).
      It can't be used to initialize lists (Without an extra list initializer).
      It can't explicitly default-initialize (Without repetition of the type).

      > When are they useful
      When you want to call a constructor that has a list constructor and a regular constructor.

      > If they're bad way, why C++ defines them to initialize variables
      Removing such a major feature is sure to break old code.

  • yeko

    when should i use copy or when should i use  uniform initialization???

  • yeko

    i think this page is so good i think i think  here  can learn c++  very well thank you much.

  • Brett

    Hey Alex I'm trying to learn C++ using these lessons and visual studio, but I came across a problem when trying to use what I learned from here and put it into visual studio. So this was what I put in:

    (PS. sorry if the code wasn't in the code tags properly, I can't tell while writing this comment.)

    And it came up with "warning C4189: 'width': local variable is initialized but not referenced"

    Can someone please explain to me what it means to be initialized but not referenced, and how to fix it, I would appreciate it a lot, and I really enjoy these lessons, keep it up.

    • Hi Brett!

      It means, that you're never using @width for anything.
      For now you can ignore it. If you see this warning later, you either forgot to implement something or you forgot to remove a variable after removing code.

    • yeko

      this mean sometimes you can't use special names width special name too so i prefer use like i don't know your name maybe or another name ut don't height width etc. use another name (but i am not sure i think you should search on the stack overflow or here!)

  • Nazo

    Should I always use uniform initialization if possible or are there cases where copy/direct initialization are better?

  • Rich

    What does "Split" mean in the table of contents

    • Alex

      Oh! It means the lesson was split into multiple lessons because it was getting too long. So content that used to be in a split lesson may now be in the subsequent lesson instead.

      • Rich

        OK thank you for getting back to me.

        Is it mainly for previous users looking up something so if they can't find it then it might have been moved?

        I've never been to the site before so can I just ignore it and go section by section as I normally would?

  • Juan

    Very interesting, I'm learning new things.

  • Hi Alex!

    >

    I'm seeing this a lot recently. Empty brackets should be used when the type is too complex or one wants to use the default constructor. Using this for built-in- or other simple types makes the code harder to understand.

    • Alex

      I kind of agree with you that scalar types are better initialized with an explicit value than through zero-initialization, but I can't find any supporting evidence of this being a general best practice. Are you aware of any such documentation?

      • > general best practice
        Is there even such thing? There will always be someone who doesn't agree.
        I do it, because it makes the coder easier to understand. The only downside being that it's more typing. One outweighs the other in my opinion.

        • Alex

          Yes, there are definitely well established practices that have been generally adopted by the community. These practices typically end up codified in style guides and coding practices documents. I've done innumerable searches to see if I can find anybody who advocates for or against the explicit initialization of scalars to 0 rather than relying on zero-initialization, and I can't find anybody recommending to not use zero-initialization in this regard.

          I'm a little torn personally -- on one hand, explicit is better than implicit. On the other hand, redundancy is bad and a breeding ground for mistakes.

          We wouldn't advocate initializing an empty string like this:

          over this:

          So why would we advocate for this:

          over this?

          We also wouldn't typically call this function:

          Like this:

          If you know that {} essentially means "initialize this object to default value", and the default value for scalars is 0, then it's not much cognitive load to understand that int x {} is implicitly zero-initializing x.

          Happy to accept counterarguments or other viewpoints here, as I'm still mulling the pros and cons of this one.

          • call different constructors, the former shouldn't be used, but I think I get your point.
            There are cases where empty brackets are better than giving explicit values (eg. class types). Since these cases occur it virtually every project, my argument that explicit initialization of scalar types makes the code easier to understand for people not familiar with cpp is no longer valid. Those people will have to understand empty brackets anyway.
            I've postponed my reply to your comment a couple of days to see if I can come up with any reasons against empty brackets, but I couldn't. I like consistent code more than I like explicit code, so I'll switch to empty brackets for zero-initialization.

            Thanks for your time! If any more (dis)advantages come to your mind, please let me know.

  • Ryan

    Hi, I've tried to use uniform initialisation but this returns an error for me. For instance, when doing the challenge at the end of the exercise, my code is:

    [code]
    # include <iostream>

    int multiply_by_2(int x)
    {
        return 2*x;
    }

    int main()
    {
        std::cout << "Enter an integer:";
        int num {0}; // define variable num for input
        std::cin >> num; // recieve input integer from user
        std::cout << "Double that number is: " << multiply_by_2(num) << '\n';
        return(0);
    }
    [\code]

    and I get the following error:

    [code]
    multply_2.cpp:11:12: error: expected ';' at end of declaration
        int num {0}; // define variable num for input
               ^
               ;
    1 error generated.
    [\code]

    I am using a MacBook, when I enter g++ --version in my terminal I get:

    [code]
    Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
    Apple LLVM version 10.0.0 (clang-1000.10.44.4)
    Target: x86_64-apple-darwin18.2.0
    Thread model: posix
    InstalledDir: /Library/Developer/CommandLineTools/usr/bin
    [\code]

    How do I get this to run correctly?

  • there is something i don't get; what is the use of an integer variable when it is in a program when we use curly braces. when i run the program i always found out that the value that i inserted in the curly braces doesn't seem to hold any value; please tell me the utility of the variable inside the curly braces

    thanks

  • Asgar

    Here is a quote (sorry, long quote) by Scott Meyers:
    "If you're an experienced C++ programmer and are anything like me, you initially approached C++11 thinking, "Yes, yes, I get it. It's C++, only more so." But as you learned more, you were surprised by the scope of the changes. auto declarations, range-based for loops, lambda expressions, and rvalue references change the face of C++, to say nothing of the new concurrency features. And then there are the idiomatic changes. 0 and typedefs are out, nullptr and alias declarations are in. Enums should now be scoped. Smart pointers are now preferable to built-in ones. Moving objects is normally better than copying them."

    He says 0 is out. What does he mean by that? We are discussing zero initialization in C++11 here and it seems 0's are still available.

Leave a Comment

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