본문 바로가기
College Study/C++ (ENG)

[C++] C++ 11/14/17/... New Keywords (ENG)

by 2den 2022. 1. 2.
728x90

 

auto

The keyword auto infers the data type automatically. It is not a dynamic type (like var of JavaScript). So you need to initialize auto's variables.

auto x;  // error
auto x = "Chris";  // OK

auto x = 50;  // error
 

 

It can get values, pointers, and even references (and so on). auto for pointers can omit *, but it's better to use * for readability of programmers. Reference types must use & so that the compiler can distinguish them.

const int b = 1;
auto& a = b;
 

In the case above, auto& contains const. But it's better to use const auto&, too.

 

Sometimes, it is used to get what the function returns. So that when the programmer needs to fix code like float to double, it is not needed to fix the type of result.

float Add(float a, float b)
{
    return a + b;
}

int main()
{
    auto result = Add(10.f, 30.f);

    return 0;
}
 

However, using auto reduces readability at the expense of reducing the amount of typing.

 

But when you use it for iterator, it is so good to use.

for (std::vector<int>::const_iterator it = v.begin(); it != v.end(); ++it){ /*...*/ }
for (auto it = v.begin(); it != v.end(); ++it){ /*...*/ }

for (std::map<std::string, std::string>::const_iterator it = v.begin();
    it != v.end(); ++it){ /*...*/ }
for (auto it = v.begin(); it!= v.end(); ++it){ /*...*/ }
 

 

It is also good for template type. (If you not read the left side of code to read types only.) It can be not good unless the real type appears close so you can check its type in a line, though.

MyArray<int>* a = new MyArray<int>(10);
auto* a = new MyArray<int>(10);
 

 

Best Practice of auto Keyword

1. Use real type instead of auto keyword.

2. Exception of number 1: Use auto keyword for template and iterator.

3. Use auto* than just auto.

4. Use const auto& than just auto&.

 

 

 

static_assert

To catch a problem during debugging, static_assert checks if the condition is correct and stops execution by crashing when the condition is not right. assert works at run time, static_assert works at compile time.

 

assert is valid only in debug builds. It disappears in release builds. You must run the program to see the failed assert. (Some assertion can be checked before execution.) The insistence of using asserts everywhere is not really wrong.

 

static_assert checks assertions during compilation. The compiler knows whether the assert condition is true or not.

 

static_assert is used to check the size of structures.

static_assert(sizeof(student) == 74, "Student structure size mismatch");
 

 

It is also used to check the version.

// class.h
class Class
{
public:
    const static int Version = 1;
    // ...
};

// Main.cpp
#include "Class.h"

static_assert(Class::Version > 1, "You need higher version than 1.");
 

 

And it is used to check the size of arrays.

static_assert(
    sizeof(mScores) / sizeof(mScores[0]) == MAX_SCORES.
    "The size of scores vector is not 10");
 

 

Best Practice of static_assert Keyword

1. Use static_assert as many times as you can instead of assert.

2. If you use assert: you have to run the program to verify the assertion and have to build with the debug mode.

3. If you use static_assert: you can immediately notice any problems during compilation.

 

 

 

default and delete

problem 1: implicit constructor

Especially the copy constructor does 'shallow copy'.

 

problem 2: empty constructor

 

Dog() = default;
 

The compiler can create specific constructors, operators, and destructors. So you don't have to specify an empty constructor or destructor And you can also make the default constructor, operator and destructor clearer.

 

We used to use the trick to set the constructor as a private member to remove(actually, to hide) the compiler-created constructor. But now you can use delete keyord to remove it.

Dog (const Dog& other) = delete;
 

Then, the problem is clearly shown in the error message.

 

Best Practice of default /delete Keyword

Just use them.

 

 

 

final

final is used to solve inheritance problems, including the problem of making destructors virtual.

// Animal.h
class Animal final
{ /*...*/ }

// Dog.h
class Dog : public Animal  // error
{ /*...*/ }
 
// Dog.h
class Dog final : public Animal
{ /*...*/ }

// Corgi.h
class Corgi : public Dog  // error
{ /*...*/ }
 

It can be used for member functions, too.

// Animal.h
class Animal
{
public:
    virtual void SetWeight(float weight) final;
    // ...
}

// Dog.h
class Dog : public Animal
{
public:
    virtual void SetWeight(int weight) override;  // error
    Dog();
    ~Dog();
};
 

As above, final keyword is used to prevent overriding classes and virtual functions in child classes. It is checked during compilation and cannot be used unless it is a virtual function.

 

+) The code below cannot be compiled.

class Animal
{
public:
    void Eat() final;
};

class Dog : public Animal
{
public:
    void Eat();  // It is overriding.
};
 

 

 

override

virtual void SetWeight (float weight);  // Animal.h
virtual void SetWeight (int weight);    // Dog.h - it is not overriding.
 

override is used to distinguish between a new function or a wrong overriding. A wrong overriding means the case that you meant to override, but you couldn't.

virtual void SetWeight (float weight) override;  // compiler will check it.
 

 

It is checked during compilation and cannot be used unless it is a virtual function.

// Animal.h
class animal
{
public:
    virtual void Set Weight (float weight);
    void PrintAll();
    // ...
};

// Dog.h
#include "Animal.h"

class Dog : public Animal
{
public:
    // OK - it guarantees that the parent is a virtual function.
    virtual void SetWeight(float weight) override;

    // Compile Error
    virtual void SetWeight(int weight) override;

    // Compile Error - it is not a virtual function
    void PrintAll() override;

    // ...
};
 

 

 

offsetof

(not a keyword)

offsetof indicates how many bytes a member is from the beginneng of the data structure that contains it. It is useful when serializing and when deserializing. You can know their offsets during compilation.

 

728x90

댓글