Advantage: Doesn't allow narrowing, i.e. the following throws an error:
int i {2.0f};
Advantage: Doesn't create a copy (practical for objects):
T a(b); // direct initialization
T a = b; // copy initialization (temporary object created from b)
T a = T(b); // similar to previous line
Alternative to passing by value because:
- Reference => Avoids making a copy, unlike pass by value.
- Constant => Cannot by modified, like pass by value.
void foo(const string& s);
It guarantees that the object it is being invoked on cannot be changed.
class MyClass {
public:
int fct(int var) const;
}
It deletes the assignment operator, unless the field is made static.
- Constants at file scope (global) or namespace scope have internal linkage (in constrast with variables which have external linkage).
- Internal linkage means it can be seen only from within its translation unit (like with
static
keyword at file scope)
- A constrexpr class field must be static, because a constexpr is evaluated at compile time, whereas a non-static field member is not initialized till runtime (when instance created).
- A static constexpr can be defined in header (in constrast to static const), because it's implicitely an inline variable.
- When the execution time of a small function is less than the switching time, the
inline
keyword tells the compiler to insert the code of the inline function where it is called. - They can be defined in class header without multiple definitions error being reported by linker.
- Allows a static field member to be initialized in header without reporting multiple definitions error (from each translation unit it's included in).
- To avoid as much as possible for a better encapsulation.
- It's encouraged for primitive types as it reduces their scope while the variable is only allocated once.
- For objects, the constructor and the destructor are called in every iteration.
- Functors (function object) are classes which implement operator().
- They operate like functions, but are capable of storing data in member variables.
- Used for sorting std::vectors and for calculating the minimum and the maximum.
class Accumulator {
private:
int m_counter{0};
public:
Accumulator() {}
int operator() (int i) {
return (m_counter += i);
}
};
int main() {
Accumulator acc;
std::cout << acc(10) << '\n'; // prints 10
std::cout << acc(20) << '\n'; // prints 30
return 0;
}
The constructor of the base class can be called in a derived class inside the member initialization list.
class Base {
private:
int m_id;
public:
Base(int id): m_id{id} {}
}
class Derived: public Base {
private:
double m_cost;
public:
Derived(int id, double cost):
Base(id), // note the call to Base's constructor
m_cost{cost}
{
}
}
When the static type of an object is different from its dynamic one (polymorphism), the destructor must be virtual or else the derived part won't be freed (source).
int i = 3;
int* p = new int; // dynamic allocation of pointer (on the heap)
p = &i;
delete p; // release storage space allocated with new
- See this introductory youtube video.
- Introduced in C++11, and are preferred to raw pointers.
- Object that wraps a raw pointer to manage its lifetime (i.e. avoids memory leaks).
- The wrapped pointer will be deleted once out of scope.
- Unique pointer:
- Cannot be copied.
- Initialize with
make_unique()
to handle exceptions.
std::vector<Type>
allocates its Type
elements on the heap (like a pointer or an array), and its header on the stack.
- Same as function pointers in C (see example below).
- There's a more convenient way to pass functions:
#include <functional>
int operation(int a, int b, std::function<int (int, int)> f) { return f(a, b) }