Should I always use auto?
Use when type is obvious or very long; not when clarity suffers (e.g., int vs double).
Master Modern C++ with comprehensive examples: C++11, C++14, C++17, C++20, and C++23 features, modern syntax, best practices, and performance improvements.
Modern C++ adds safety and expressiveness—auto, lambdas, move semantics, and smart pointers. Learn idioms employers expect in code written after 2011.
Teams expect modern idioms. Interviewers ask about move, lambda captures, and why unique_ptr matters.
Modern C++ refers to C++ standards from C++11 onward, which introduced revolutionary features that transformed how C++ is written. These features make code safer, more expressive, and more efficient.
Auto type deduction, lambda expressions, smart pointers, move semantics, range-based for loops
Generic lambdas, variable templates, digit separators, return type deduction
Structured bindings, if constexpr, fold expressions, filesystem library
Concepts, ranges, coroutines, modules, three-way comparison
std::expected, std::print, deducing this, stacktrace library
C++11 was a monumental update that fundamentally changed how C++ is written. It introduced features that make C++ safer, more expressive, and more efficient.
// Auto type deduction
auto x = 5; // x is int
auto y = 3.14; // y is double
auto z = "hello"; // z is const char*
// Range-based for loops
for (auto& item : container) { }
// Lambda expressions
auto lambda = [](int x) { return x * x; };
// Smart pointers
auto ptr = std::make_unique(42);
auto shared = std::make_shared(100);
// Move semantics
std::vector v1 = {1, 2, 3};
std::vector v2 = std::move(v1); // Move, not copy
auto x = 5;
auto name = string("C++");vector v={1,2,3};
for (auto n : v) cout << n; auto sq = [](int x){ return x*x; };auto p = make_unique(42); vector a={1,2};
vector b = move(a); int* p = nullptr;auto when type is obvious from contextnullptr instead of NULLenum class for type-safe enumerationsauto when type isn't clearnoexceptshared_ptr when unique_ptr sufficesweak_ptr has expiredC++14 built upon C++11 with smaller but significant improvements that made the language more convenient and powerful.
// Generic lambdas
auto lambda = [](auto x, auto y) { return x + y; };
// Return type deduction for normal functions
auto add(int a, int b) {
return a + b; // return type deduced as int
}
// Binary literals and digit separators
int binary = 0b1010'1010;
int large = 1'000'000'000;
// Variable templates
template<typename T>
constexpr T pi = T(3.1415926535897932385L);
// std::make_unique (actually C++14, not C++11)
auto ptr = std::make_unique<int>(42);
auto add = [](auto a, auto b){ return a+b; };auto mul(int a,int b) { return a*b; }int flags = 0b1010;long big = 1'000'000;auto p = make_unique("hi"); int old = exchange(x, 0);C++17 added significant features that make C++ more expressive, safe, and convenient for modern programming.
std::pair<int, std::string> p{1, "one"};
auto [id, name] = p;
// id = 1, name = "one"
std::map<int, std::string> m{{1, "one"}, {2, "two"}};
for (const auto& [key, value] : m) {
// Use key and value
}
template<typename T>
void process(T value) {
if constexpr (is_integral_v<T>) {
// Compile-time branch
cout << "Integer: " << value;
} else if constexpr (is_floating_point_v<T>) {
cout << "Float: " << value;
} else {
cout << "Other: " << value;
}
}
template<typename... Args>
auto sum(Args... args) {
return (... + args); // Fold expression
}
template<typename... Args>
bool allTrue(Args... args) {
return (... && args); // Logical AND fold
}
pair p={1,"a"};
auto [id,name] = p; if (auto it = m.find(k); it != m.end())
cout << it->second;optional o = 5;
if (o) cout << *o; string_view sv = "hello";if (exists("data.txt")) cout << "found";template
auto sum(Ts... xs){ return (xs + ...); } C++20 introduced game-changing features that fundamentally transform template programming, ranges, concurrency, and module systems.
// Concepts
template<typename T>
concept Integral = is_integral_v<T>;
template<Integral T>
T square(T x) { return x * x; }
// Ranges
vector<int> numbers{1, 2, 3, 4, 5};
auto even = numbers | views::filter([](int n){ return n % 2 == 0; });
// Coroutines
generator<int> range(int start, int end) {
for (int i = start; i < end; ++i)
co_yield i;
}
// Three-way comparison (spaceship operator)
auto operator<=>(const Point&) const = default;
template
concept Addable = requires(T a,T b){ a+b; }; vector v={3,1,2};
ranges::sort(v);cout << format("x={}", 42);int arr[]={1,2,3};
span s(arr); auto cmp = 5 <=> 3; // strong_ordering// co_await, co_yield (advanced)std::format for type-safe string formattingstd::span for non-owning views of contiguous dataC++23 continues the evolution with practical improvements, new library features, and enhancements to existing functionality.
// std::expected for error handling
std::expected<int, std::string> parseNumber(std::string_view s);
// std::print for easier output
std::print("Hello, {}!", name);
// Deducing this
struct Widget {
void process(this auto&& self) {
// self is deduced
}
};
// std::stacktrace for debugging
auto trace = std::stacktrace::current();
expected ok = 42;
if (ok) cout << *ok; print("Hello {}
", name);auto v = views::iota(1,5) | views::transform([](int x){return x*2;});struct S { this auto& self() { return *this; } };// flat_map in draft/stdlib extensions// import std; // toolchain dependentSmart pointers automate memory management, preventing memory leaks and making code exception-safe. Modern C++ provides three main smart pointers.
Exclusive ownership. Cannot be copied, only moved.
auto ptr = make_unique<T>(args);
auto moved = std::move(ptr);
// ptr is now nullptr
// Custom deleter
auto ptr = unique_ptr<FILE,
decltype(&fclose)>(fopen(...), fclose);
Shared ownership. Reference counted.
auto ptr = make_shared<T>(args);
auto copy = ptr; // Ref count: 2
copy.reset(); // Ref count: 1
// Control block stores ref count
// Atomic operations for thread safety
Non-owning reference to shared_ptr.
weak_ptr<T> weak = shared;
if (auto locked = weak.lock()) {
// Use locked shared_ptr
} else {
// Object was destroyed
}
auto p = make_unique(); auto s = make_shared(); void take(unique_ptr f) {} cout << s.use_count();weak_ptr w = s;
if (auto locked = w.lock()) {} // prefer make_* over new/deleteunique_ptr for exclusive ownership (default choice)shared_ptr only when shared ownership is truly neededweak_ptr to break reference cycles and for cachingmake_unique and make_shared over explicit newenable_shared_from_this when objects need to create shared_ptr to themselvesint* p = new int(5);
delete p;auto p = make_unique(5); char* s = NULL;char* s = nullptr;typedef vector IntVec; using IntVec = vector; Use when type is obvious or very long; not when clarity suffers (e.g., int vs double).
Casts to rvalue reference to enable move instead of copy—does not move by itself.
auto, lambdas, smart pointers, nullptr, range-for, move semantics—foundation of ‘modern C++.’