Assingment vs. Initialization in C++
Tags: cpp, todayilearned
Published: 2021-01-05 23:09:15

This is going to be my first post so I chose a rather simple concept: Assignment vs Initialization in C++. I will try to keep the post as practical as possible and share keywords in case the reader wants to do in-depth research. So buckle up and enjoy the ride folks!

```c++
int x;     // Define x
x = 3;     // Assign 3 to x

int y{3}; // Define and initialize y with 3
```

Above statements cause both x and y variables to have a value of 3, which leads to the common pitfall that they are identical. 

Let's wear ISO C++ Standards Committee hat ![Formal Hat](https://www.cotswoldcountryhats.com/ekmps/shops/speedmaster/resources/Design/category-formal-hats-1920-x-838.jpg)
According to C++20 standards, which is recently published, initialization is explained in "9.4 Initializers" section; whereas assignment is explained in "11.4.5 Assignment operator" section. How dare you call them identical, you peasant!

That was a little bit harsh. Perhaps we should wear C++ compiler implementer hat ![Fedora hat](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSQb-lNWUcFVDB7sX1APsT1DA8wOV_r2rEfRANx0XI27O4l5WCh8TQ_1Q4JGX22ZrS2GsdP12P_u745AHy2Qcj1zK10bNPQOjz4Dg&usqp=CAU&ec=45750089)
Gcc 10.2 produces **identical** output for below codes with or without optimizations.
```c++
int getX(){
    int x {3};
    return x;
}

int getY(){
    int y;
    y = 3;
    return y;
}
```

```assembler
get():
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 3
        mov     eax, DWORD PTR [rbp-4]
        pop     rbp
        ret
```

That was a bit anticlimactic, I guess. My guess is if data type is scalar, compiler can directly assign value as [cppreference.com](https://en.cppreference.com/w/cpp/language/operator_assignment) suggests but I couldn't find the relevant section (direct assignment) on c++ standard. Perhaps we should try a non-scalar data type. For example std::string.

```c++
#include <string>
std::string getX(){
    std::string x {"bugra"};
    return x;
}

std::string getY(){
    std::string x;
    x = "bugra";
    return x;
}
```

Let's see what GCC 10.2 produce for getX and getY with optimizations enabled.
```assembly
getX[abi:cxx11]():
        lea     rdx, [rdi+16]
        mov     BYTE PTR [rdi+20], 97
        mov     rax, rdi
        mov     QWORD PTR [rdi], rdx
        mov     DWORD PTR [rdi+16], 1919382882
        mov     QWORD PTR [rdi+8], 5
        mov     BYTE PTR [rdi+21], 0
        ret
```
```assembly
.LC0:
        .string "bugra"
getY[abi:cxx11]():
        push    r12
        mov     r8d, 5
        mov     ecx, OFFSET FLAT:.LC0
        xor     edx, edx
        push    rbp
        xor     esi, esi
        mov     r12, rdi
        push    rbx
        lea     rbx, [rdi+16]
        mov     QWORD PTR [rdi], rbx
        mov     QWORD PTR [rdi+8], 0
        mov     BYTE PTR [rdi+16], 0
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_replace(unsigned long, unsigned long, char const*, unsigned long)
        mov     rax, r12
        pop     rbx
        pop     rbp
        pop     r12
        ret
        mov     rbp, rax
        jmp     .L2
getY[abi:cxx11]() [clone .cold]:
```

I am no expert but I think getX (initializing method) is a lot better than getY (assignment method). Since we established that assignment and initializing can cause different outputs to be produced, let's try to understand the difference between them. We need to wear the formal hat again.

C++20 standard "6.7.7 Temporary objects" section states that the expression a = f() requires a temporary object for the result of f(), which is materialized so that the reference parameter of X::operator=(const X&) can bind to it.

[Cpp Core Guidelines](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-initialize) also advices to prefer initalization to assignment.

Let's finish with a regular developer hat ![Dev hat](https://footwearnews.com/wp-content/uploads/2020/05/virgil.jpg?w=1024)

**TLDR: Prefer initialization to assignment!**

```C++
class A {   // Good
    string s1;
public:
    A(string p) : s1{p} { }    // GOOD: directly construct 
};

class B {   // BAD
    string s1;
public:
    B(const char* p) { s1 = p; }   // BAD: default constructor followed by assignment
};
```


Keywords:  copy assignment, Builtin direct assignment for scalar types, copy initialization, direct initialization,  list-initialization, temporary objects

[ISO C++20 Standard](https://isocpp.org/files/papers/N4860.pdf)