Introduction
C++ has changed a great deal since 2011. Modern C++ code looks very different from older code, and is much safer, because the language now lets objects take care of their own cleanup. This lesson shows the habits you will see in current code.
How it works
auto and range-based for cut down on noise. for (const auto& item : items) reads every item with no copying and no index.
enum class names a set of options. Unlike a plain enum, its values must be written with the type's name, as in Status::Paid, and they do not turn into integers by accident.
Destructors and RAII. A destructor, written ~Name(), runs automatically when an object goes away. If an object acquires something in its constructor and releases it in its destructor, the release cannot be forgotten. That is RAII, and it is why vector and ifstream need no cleanup code.
#include <iostream>
#include <string>
using namespace std;
class Logger {
string name;
public:
Logger(const string& n) : name(n) {
cout << "start " << name << endl;
}
~Logger() {
cout << "end " << name << endl;
}
};
int main() {
Logger a("outer");
{
Logger b("inner");
cout << "working" << endl;
}
cout << "back" << endl;
return 0;
}Objects are destroyed in the reverse of the order in which they were created.
Smart pointers. When you truly need an object on the heap, unique_ptr owns it and deletes it automatically.
#include <memory>
auto p = make_unique<int>(5); // freed automatically
cout << *p << endl;
Lambdas are small functions written where they are needed, most often for algorithms.
int limit = 3;
int n = count_if(v.begin(), v.end(), [limit](int x) { return x > limit; });
The part in square brackets says which local variables the function can use.
A note on this site. StepVioz's editor does not yet run smart pointers or lambdas, so these two snippets cannot be stepped through here. They were tested with the real g++ compiler. In this course, pass a named function to an algorithm instead, which works everywhere.
Syntax
enum class Colour { Red, Green };
Colour c = Colour::Red;
class File {
public:
File() { /* acquire */ }
~File() { /* release */ }
};
Example
#include <iostream>
#include <map>
#include <string>
using namespace std;
enum class Status { New, Paid };
string text_of(Status s) {
return s == Status::New ? "new" : "paid";
}
int main() {
map<int, Status> orders;
orders[1] = Status::New;
orders[2] = Status::Paid;
for (const auto& order : orders) {
cout << order.first << " " << text_of(order.second) << endl;
}
return 0;
}Line by line
enum class Statusdefines two named options.text_ofturns one into text for printing.ordersmaps an order number to its status.- The values must be written
Status::New, with the type's name. - The loop uses
const auto&, and prints each order in key order.
Expected result
1 new
2 paid
In the real world
Most C++ style guides now forbid raw new and delete in everyday code. RAII also manages locks, network connections and files, so that they are released correctly even when errors occur.
Common mistakes
- Using
autowhere the type is not clear, which makes the code harder to read. - Forgetting
&infor (auto x : big_items), which copies each item. - Writing a destructor but copying the object carelessly, so that a resource is released twice.
- Using a plain
enumwhereenum classwould catch mistakes.
Best practices
- Let containers and smart pointers own memory.
- Use
const auto&for loops over large items. - Give every resource an owner object.
Summary
Modern C++ uses auto, range-based for and enum class for clearer code. Destructors make RAII possible, so resources are released automatically. Smart pointers and lambdas are the standard tools in current code.
Quick check
Key takeaways
- Let objects manage their own resources.
- Prefer enum class for safer named constants.
- Prefer unique_ptr to raw new and delete.
Practice problems for this lesson
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.