# Const correctness

## Что почитать про const?

Использование **const** в **C++** крайне важно. Кто не знаком с данной темой, рекомендую про **const correctness** все прочитать:

1\. [News, Status & Discussion about Standard C++](https://isocpp.org/wiki/faq/const-correctness)

2\. **Правило 3: Везде, где только можно, используйте const** в книге _Эффективное использование С++. 55 верных способов улучшить структуру и код ваших программ | Мейерс Скотт_

## Сonst в объявлении функций

Функции, которые не изменяют внутреннее состояние объекта важно помечать **const**. Это позволит избежать кучу потенциальных ошибок на уровне компиляции. Дополнительно, при виде **const** другой разработчик при чтении сразу понимает, что функция ничего не изменяет внутри объекта:

```cpp
bool GetHealth() const { return Health; } 
```

## Const при объявлении перменной

Аналогичо, если мы не планируем менять значение перменной — добавляем к ней **const.** \
Простейший пример — мы совершили ошибку, вместо оператора сравнения **==** использовали оператор присваивания **=**

```cpp
// без const присваивание произойдет, данный код скомпилируется
int var1 = 12;
if(var1 = 13)
{
}

// с использованием const, данная ошибка будет выявлена на уровне компиляции,
// изменить значение константы нельзя
const int var2 = 12;
if(var2 = 13)
{
}
```

## Использование константной ссылки в параметрах функции

При передаче по константной ссылке, мы не создаем копию объекта при вызове функции. В большинстве случаев это не повлияет на работу программы (из-за размера объекта или из-за отсутсвия  конструктора копирования), но лучше сразу приучать себя к правильному стилю, это позволит избежать ошибок в более сложных случаях.

Рассмотрим пример (рекомендую создать консольное приложение в **VS** или протестировать онлайн — [пример по ссылке](https://www.onlinegdb.com/9oWtDMI_4)):

```cpp
#include <iostream>
 
class MyOwnType
{
public:
    MyOwnType()
    {
         std::cout << "constructor call!"<< std::endl;
    }
 
    MyOwnType(const MyOwnType&)
    {
        std::cout << "copy constructor call!"<< std::endl;
        for(int i = 0; i < 10; ++i)
        {
            std::cout << i << std::endl;
        }
         
    }
 
    ~MyOwnType()
    {
        std::cout << "de-structor call!"<< std::endl;
    }
};
 
void func1(MyOwnType type)
{
    std::cout << "func1 call!"<< std::endl;
}
 
void func2(const MyOwnType& type)
{
    std::cout << "func2 call!"<< std::endl;
}
 
int main()
{
    MyOwnType myOwnObj;
    std::cout << "==========func1============="<< std::endl;
    func1(myOwnObj);
    std::cout << "===========func2============"<< std::endl;
    func2(myOwnObj);
 
    std::cout << "===========end of program============"<< std::endl;
}
```

В консоль выведется следующее:

```cpp
constructor call!
==========func1=============
copy constructor call!
0
1
2
3
4
5
6
7
8
9
func1 call!
de-structor call!
===========func2============
func2 call!
===========end of program============
de-structor call!
```

Что произошло?:

1\. Вызвался конструктор при создании объекта **MyOwnType myOwnObj;**

```cpp
constructor call! 
```

2\. Вызываем первую функцию, без константной ссылки: у нас вызвался конструктор копирования (где может быть достаточно сложное и глубокое копирование в общем случае) и на выходе из функции объект уничтожается, вызывается деструктор. То есть произошло два дополнительных вызова функции внутри:

```cpp
==========func1=============
copy constructor call!
0
1
2
3
4
5
6
7
8
9
func1 call!
de-structor call!
```

3\. Вызываем вторую функцию, по константной ссылке: конструктор копирования не вызывается, так же как и деструктор:

```cpp
===========func2============
func2 call!
```

4\. Вызвался деструктор нашего объекта, который мы создали в начале:

```cpp
===========end of program============
de-structor call!
```
