Stefano Lusardi, Software Developer
Modern: C++11 Standard and beyond
Practices: readable, expressive, solid, reusable pieces of code
We will discuss only STL although Boost, Qt and others third party provides even wider set of features
The simplest example: loop comparison
Non-standard vs. standard implementation in practice
Remember that we are looking for:
Example: "Old school" for loop
int c = 0;
for (int i = 0; i < myVec.size(); ++i) {
myVec[i] == 5 && ++c;
}
How many times have you seen something like this (but ten times more complex)?
To fully understand this snippet you need at least to read it once entirely
Example: "New school" standard algorithm
int c = std::count(begin(myVec), end(myVec), 5);
Isn't it clearer, shorter, more expressive and bullet proof?
You can understand its meaning even without read it entirely!
What does your (modern) compiler do for you?
Automatic generation of Special Member Functions
All Special Member Functions
class Foo{
Foo(); // 1. Default Constructor
~Foo(); // 2. Destructor
Foo(const Foo&); // 3. Copy Constructor
Foo& operator=(const Foo&); // 4. Copy Assignment
Foo(Foo&&); // 5. Move Constructor
Foo& operator=(Foo&&); // 6. Move Assignment
};
Partial Special Member Functions
// What you write:
class Bar {
Bar(const Bar& bar, int i = 0);
// This counts as user defined copy constructor since
// the second argument is defaulted
};
// What you get:
class Bar {
//1. No Default Constructor: we have a user defined ctor
~Bar(); // 2. Destructor
Bar(const Bar&); // 3. Copy Constructor
Bar& operator=(const Bar&); // 4. Copy Assignment
// 5. No Move Constructor: we have a user defined copy ctor
// 6. No Move Assignment: we have a user defined copy ctor
};
Use the Rule of 3 (or 5):
"If a class requires a user-defined destructor, a user-defined copy constructor, or a user-defined copy assignment operator, it almost certainly requires all three."
from cppreference.com
default and delete specifiers
struct Foo{
Foo(double radius) { }
Foo(Foo& c) = delete;
Foo& operator=(Foo& c) = delete;
};
int main(){
Foo f1; // KO: No default ctor
Foo f2(2); // -OK-
f2 = f2; // KO: No copy assignament
Foo f3(f2); // KO: No copy ctor
Foo f4 = f2; // KO: No copy ctor
return 0;
}
Do you still need a private copy ctor/assignment?
No, just delete them!
Explicit constructor specifier
struct Circle{
// Not Explicit ctor
Circle(double radius) : mRadius{radius} { }
double Area() const { return mRadius * mRadius * PI; }
double mRadius;
};
struct Square{
// Explicit ctor
explicit Square(double side) : mSide{side} { }
double Area() const { return mSide * mSide; }
double mSide;
};
double Area(Circle c){ return c.Area(); }
double Area(Square s){ return s.Area(); }
int main(){
Circle c(4);
Square s(4);
std::cout << "Circle Area: " << Area(c) << "\n";
std::cout << "Square Area: " << Area(s) << "\n";
std::cout << "Which Area?: " << Area(4) << "\n";
return 0;
}
RVO (Return Value Optimization)
Generating useless copies: why do we care?
g++ -std=c++11 -fno-elide-constructors -O2 -pedantic -pthread main.cpp && ./a.out example on coliru.com
struct C {
C() {}
C(const C&) { std::cout << "A copy was made.\n"; }
};
C f() {
return C();
}
int main() {
C c = f();
}