Python Java C++ HTML CSS Bootstrap JavaScript jQuery AngularJS React Node.js TypeScript Django NumPy Pandas Matplotlib Seaborn Machine Learning Deep Learning Decipher XML

Introduction to C++

C++ is a high-performance, compiled programming language built on top of C with support for object-oriented, generic, and functional styles. It was developed by Bjarne Stroustrup.

Use C++ when you need speed, low-level control, and modern abstractions. It is widely used in competitive programming, game engines, systems, embedded software, and finance.

C++ offers fine-grained control over memory and performance while providing modern features like templates, RAII, and the Standard Library (STL).

Compilation Model

C++ code is typically compiled into machine code. The pipeline involves preprocessing, compilation, assembly, and linking.

// Compile and run (example)
// g++ main.cpp -O2 -std=c++17 -o app
// ./app
      

Core Building Blocks

#include <iostream>   // header: standard input/output
using namespace std;  // avoid in headers; ok for small examples

int main() {           // program entry point
    cout << "Hello, C++!";
    return 0;          // return status code
}
      

Memory & Resource Management (RAII)

RAII ties resource lifetime to object scope, reducing leaks and errors.

#include <vector>
void demo() {
    std::vector<int> v = {1,2,3}; // memory managed automatically
} // v is cleaned up here
      

Standard Library (STL)

The STL provides containers, algorithms, iterators, and utilities.

#include <algorithm>
#include <vector>
std::vector<int> a = {3,1,2};
std::sort(a.begin(), a.end());
      

Headers, Declarations, and Definitions

Use headers for declarations and source files for definitions. This keeps builds fast and avoids multiple-definition errors.

// math_utils.h
int add(int a, int b); // declaration

// math_utils.cpp
int add(int a, int b) { return a + b; } // definition
      

Translation Units & Linking

Each .cpp file is compiled into a translation unit. The linker combines them into one executable.

// Compile separately then link
// g++ -c main.cpp
// g++ -c math_utils.cpp
// g++ main.o math_utils.o -o app
      

Namespaces

Namespaces prevent name collisions in large projects.

namespace util {
    int clamp(int x, int lo, int hi) { return x < lo ? lo : (x > hi ? hi : x); }
}
int v = util::clamp(5, 0, 3);
      

Modern C++ Features (Brief)

auto x = 10;                   // type inference
const std::string& name = "C++"; // const reference
std::vector<int> v = {1,2,3};
for (int n : v) { /* range-for */ }
      

Common Build Flags

Use a modern standard and enable warnings.

// g++ main.cpp -std=c++17 -Wall -Wextra -O2 -o app
      

Object Model (Very Brief)

Classes can include data members and functions. Objects may live on the stack or heap, and the compiler lays out members in memory.

struct Point { double x, y; };
Point p{1.0, 2.0};        // stack
Point* q = new Point{3,4}; // heap (remember delete)
delete q;
      

Const Correctness

Use const to express intent and enable compiler optimizations.

void print(const std::string& s) { std::cout << s; }
const int limit = 100;
      

Error Handling (Basics)

C++ uses exceptions for error handling and noexcept to mark functions that never throw.

double safe_div(double a, double b) {
    if (b == 0) throw std::runtime_error("divide by zero");
    return a / b;
}
      

Move Semantics (Concept)

Moves allow transferring resources instead of copying, improving performance for large objects.

std::vector<int> make() {
    std::vector<int> v = {1,2,3};
    return v; // move elision / move
}
      
#include <iostream>
using namespace std;

int main() {
    cout << "Hello, C++!";
    return 0;
}
      

Basic Syntax and Data Types

This section covers fundamental syntax, built-in types, and best practices for variable declarations in C++.

Variables and Types

int age = 21;
double salary = 35000.75;
char grade = 'A';
bool isActive = true;
string name = "Nafees";
      

Type Sizes (Platform Dependent)

Sizes vary by compiler/architecture. Use sizeof to inspect.

cout << sizeof(int) << " bytes" << endl;
cout << sizeof(long) << " bytes" << endl;
cout << sizeof(long long) << " bytes" << endl;
      

Type Inference (auto)

auto count = 10;        // int
auto price = 19.99;     // double
auto letter = 'Z';      // char
      

Signed vs Unsigned

Unsigned types store only non-negative values and can overflow differently than signed types.

unsigned int u = 10u;
int s = -5;
      

Strings

std::string full = "C++";
full += " Language";
cout << full << endl;
      

Initialization Styles

Uniform initialization helps avoid narrowing conversions.

int a = 5;
int b(5);
int c{5};  // preferred
      

Constants and Input/Output

const float PI = 3.14159f;
cout << "Enter radius: ";
float r;
cin >> r;
cout << "Area: " << PI * r * r;
      

Const and constexpr

const is runtime constant, constexpr can be evaluated at compile time.

const int maxUsers = 100;
constexpr int maxBuf = 256;
      

Input Safety

Prefer std::getline for full-line input.

std::string line;
std::getline(std::cin, line);
      

Operators

Operators are symbols that act on operands (values or variables). C++ has a rich set of operators, and understanding categories, precedence, associativity, and short-circuit behavior is key to writing correct and readable code.

1) Arithmetic Operators

Work on numeric types. Integer division truncates toward zero.

int a = 10, b = 3;
cout << (a + b) << endl;  // 13
cout << (a - b) << endl;  // 7
cout << (a * b) << endl;  // 30
cout << (a / b) << endl;  // 3 (integer division)
cout << (a % b) << endl;  // 1 (remainder)
      

For floating-point division, make at least one operand a float/double.

double x = 10.0;
double y = 3.0;
cout << (x / y) << endl;  // 3.333...
      

2) Relational and Equality Operators

Compare values and produce a boolean result.

int p = 5, q = 7;
cout << (p < q) << endl;   // 1 (true)
cout << (p >= q) << endl;  // 0 (false)
cout << (p == q) << endl;  // equality
cout << (p != q) << endl;  // inequality
      

3) Logical Operators

Combine boolean expressions. && and || are short-circuiting: the right side is evaluated only if needed.

int age = 19;
bool hasId = true;
if (age >= 18 && hasId) {
    cout << "Allowed";
}
      

4) Assignment and Compound Assignment

Assign a value to a variable. Compound operators modify and assign in one step.

int score = 10;
score = 20;   // assignment
score += 5;   // score = score + 5
score *= 2;   // score = score * 2
      

5) Increment and Decrement

Prefix changes the value first, postfix returns the old value. Prefer prefix when you do not need the old value.

int i = 5;
cout << ++i << endl;  // 6
cout << i++ << endl;  // 6 (then i becomes 7)
      

6) Bitwise Operators

Operate on individual bits of integral types.

unsigned int m = 5;   // 0101
unsigned int n = 3;   // 0011
cout << (m & n) << endl;  // 1  (0001)
cout << (m | n) << endl;  // 7  (0111)
cout << (m ^ n) << endl;  // 6  (0110)
cout << (~m) << endl;     // bitwise NOT
cout << (m << 1) << endl; // 10 (1010)
cout << (m >> 1) << endl; // 2  (0010)
      

7) Ternary (Conditional) Operator

Shorthand for simple if-else expressions.

int a1 = 8, b1 = 12;
int maxVal = (a1 > b1) ? a1 : b1;
cout << maxVal << endl;
      

8) Sizeof and Type Casting

sizeof returns the size (in bytes) of a type or object.

cout << sizeof(int) << endl;
cout << sizeof(double) << endl;
      

Use explicit casting when needed. Prefer static_cast.

int total = 7;
int count = 2;
double avg = static_cast<double>(total) / count; // 3.5
      

9) Operator Precedence and Associativity

Precedence decides which operators are evaluated first. Use parentheses for clarity. Example: multiplication happens before addition, and logical NOT happens before AND/OR.

int r = 2 + 3 * 4;        // 14, not 20
bool ok = !false || true; // true
      

10) Common Pitfalls

  • Integer division truncation: 5 / 2 becomes 2.
  • Operator precedence confusion: use parentheses to make intent obvious.
  • Mixing signed and unsigned can cause unexpected comparisons.
  • Overusing postfix increment in expressions can reduce readability.

Control Flow

Control flow determines the order in which statements execute. C++ provides branching, looping, and jump statements to build logic that responds to conditions and repeats work efficiently.

1) If / Else If / Else

Choose one path based on conditions evaluated top-to-bottom.

int marks = 72;
if (marks >= 90) {
    cout << "A";
} else if (marks >= 75) {
    cout << "B";
} else {
    cout << "C";
}
      

You can combine conditions with logical operators and use parentheses for clarity.

int age = 20;
bool hasId = true;
if ((age >= 18 && hasId) || age >= 60) {
    cout << "Allowed";
}
      

2) Switch Statement

Best for discrete values. Use break to avoid fall-through.

int day = 2;
switch (day) {
    case 1: cout << "Mon"; break;
    case 2: cout << "Tue"; break;
    case 3: cout << "Wed"; break;
    default: cout << "Invalid";
}
      

Intentional fall-through can be used but should be obvious and rare.

int month = 1;
switch (month) {
    case 1: cout << "Jan ";
    case 2: cout << "Feb ";
    case 3: cout << "Mar ";
            break;
    default: cout << "Other";
}
      

3) Loops: for, while, do-while

Use for when the iteration count is known, while for condition-based loops.

for (int i = 1; i <= 5; i++) {
    cout << i << " ";
}

int n = 3;
while (n > 0) {
    cout << n-- << " ";
}

int k = 0;
do {
    cout << k++ << " ";
} while (k < 3);
      

4) Range-Based for

Clean iteration over arrays and containers.

int nums[] = {10, 20, 30};
for (int v : nums) {
    cout << v << " ";
}
      

5) break and continue

break exits a loop; continue skips to the next iteration.

for (int i = 1; i <= 5; i++) {
    if (i == 3) continue;
    if (i == 5) break;
    cout << i << " ";
}
      

6) Nested Loops and Early Exit

Use flags or functions to break out of deep nesting cleanly.

bool found = false;
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        if (i + j == 3) { found = true; break; }
    }
    if (found) break;
}
      

7) Common Pitfalls

  • Forgetting break in switch (unintentional fall-through).
  • Off-by-one errors in loop conditions (< vs <=).
  • Using assignment in conditions by mistake: if (x = 5).
  • Infinite loops due to missing updates or wrong conditions.

Functions

Functions let you organize code into reusable blocks. Good function design improves readability, testability, and performance. Below are core and advanced concepts commonly used in modern C++.

1) Basic Function and Return

int add(int x, int y) {
    return x + y;
}

int main() {
    cout << add(4, 7);
    return 0;
}
      

2) Function Prototypes (Declarations)

Declare functions before use to avoid ordering issues.

int multiply(int a, int b); // prototype

int main() {
    cout << multiply(3, 5);
}

int multiply(int a, int b) {
    return a * b;
}
      

3) Pass by Value vs Reference

Use references to avoid copying large objects and to allow modification.

void increment(int& n) { n++; }
void show(const string& s) { cout << s; }

int a = 10;
increment(a); // a becomes 11
      

4) Default Arguments

Provide default values for optional parameters.

int power(int base, int exp = 2) {
    int result = 1;
    for (int i = 0; i < exp; i++) result *= base;
    return result;
}
cout << power(5) << endl;    // 25
cout << power(5, 3) << endl; // 125
      

Function Overloading

int sum(int a, int b) { return a + b; }
double sum(double a, double b) { return a + b; }
      

5) Inline and constexpr Functions

inline suggests removing call overhead for small functions. constexpr allows compile-time evaluation when possible.

inline int sqr(int x) { return x * x; }
constexpr int maxUsers() { return 100; }
      

6) Recursion

A function calling itself. Always ensure a base case to stop.

int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}
      

7) Returning Multiple Values

Use structs or pairs to return more than one value.

struct Stats { int minVal; int maxVal; };
Stats range(int a, int b) {
    Stats s;
    s.minVal = (a < b) ? a : b;
    s.maxVal = (a > b) ? a : b;
    return s;
}
      

8) Function Pointers and Callbacks (Preview)

Functions can be passed as parameters for flexible behavior.

int apply(int x, int (*op)(int)) { return op(x); }
int triple(int x) { return x * 3; }
cout << apply(4, triple) << endl; // 12
      

9) Best Practices

  • Keep functions small and focused (single responsibility).
  • Prefer const references for read-only parameters.
  • Avoid global variables; pass data explicitly.
  • Name functions clearly to reflect intent.

Arrays and Strings

Arrays store a fixed number of elements of the same type in contiguous memory. Strings in modern C++ are usually handled with std::string, which manages memory automatically and offers rich utilities.

1) Static Arrays

int arr[5] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; i++) cout << arr[i] << " ";
      

Array size is fixed at compile time. Access with arr[index].

2) Multi-Dimensional Arrays

int matrix[2][3] = {
    {1, 2, 3},
    {4, 5, 6}
};
cout << matrix[1][2] << endl; // 6
      

3) Range-Based for and Size

Use range-based loops and sizeof to compute length.

int nums[] = {2, 4, 6, 8};
int n = sizeof(nums) / sizeof(nums[0]);
for (int v : nums) cout << v << " ";
cout << "Size: " << n << endl;
      

4) C-Strings (Character Arrays)

C-style strings end with a null character '\0'.

char name[] = "Technacode";
cout << name << endl;
      

5) std::string Basics

string msg = "Technacode";
cout << msg.length() << endl;
cout << msg[0] << endl; // T
      

6) String Operations

string first = "Tech";
string second = "nacode";
string full = first + second;
cout << full << endl;      // Technacode
cout << full.substr(0, 4) << endl; // Tech
      

7) Input with Strings

Use getline to read full lines including spaces.

string line;
getline(cin, line);
cout << line;
      

8) Common Pitfalls

  • Accessing out-of-bounds indices causes undefined behavior.
  • Confusing std::string with C-strings.
  • Forgetting that arrays don’t know their own size.
  • Using cin >> will stop at spaces.

Pointers and References

Pointers store memory addresses, while references are aliases to existing variables. Both are essential for low-level control, performance, and working with dynamic memory.

1) Basic Pointers

int x = 10;
int* ptr = &x;        // ptr holds address of x
cout << *ptr << endl;  // dereference to read value
*ptr = 20;            // modify x via pointer
cout << x << endl;     // 20
      

2) References

References must be initialized and cannot be reseated.

int y = 5;
int& ref = y;   // ref is another name for y
ref = 12;
cout << y << endl; // 12
      

3) Null Pointers

Use nullptr to represent "no address".

int* p = nullptr;
if (p == nullptr) {
    cout << "Pointer is null";
}
      

4) Pointer Arithmetic

Advancing pointers moves by element size, not by bytes.

int arr[] = {10, 20, 30};
int* pArr = arr;
cout << *pArr << endl;      // 10
cout << *(pArr + 1) << endl; // 20
      

5) const with Pointers

Control whether the pointer or the value is constant.

const int* ptrToConst = &x; // value can't change via ptr
int* const constPtr = &x;   // pointer can't point elsewhere
      

6) Passing by Reference and Pointer

void swapByRef(int& a, int& b) {
    int t = a; a = b; b = t;
}

void swapByPtr(int* a, int* b) {
    int t = *a; *a = *b; *b = t;
}
      

7) Dynamic Memory (Preview)

Allocate on the heap with new, release with delete.

int* dyn = new int(42);
cout << *dyn << endl;
delete dyn;
      
In modern C++, prefer smart pointers like std::unique_ptr and std::shared_ptr.

8) Common Pitfalls

  • Dereferencing uninitialized or null pointers.
  • Dangling pointers after delete.
  • Returning references to local variables.
  • Confusing * (pointer) with & (address/reference).

Object-Oriented Programming

Object-Oriented Programming (OOP) models real-world entities using classes and objects. Core ideas include encapsulation, inheritance, and polymorphism.

1) Class and Object (Encapsulation)

Keep data private and expose behavior through public methods.

class Student {
private:
    string name;
    int age;

public:
    Student(string n, int a) : name(n), age(a) {}
    void show() const { cout << name << " " << age; }
};

Student s1("Aman", 19);
s1.show();
      

2) Constructors and Destructor

Constructors initialize objects; destructors clean up.

class Box {
public:
    Box() { cout << "Default\n"; }
    Box(int w, int h) : width(w), height(h) {}
    ~Box() { cout << "Destroyed\n"; }

private:
    int width = 0;
    int height = 0;
};
      

3) Inheritance

Reuse and extend behavior from base classes.

class Person {
public:
    void speak() { cout << "Hello\n"; }
};

class Employee : public Person {
public:
    void role() { cout << "Developer\n"; }
};
      

4) Polymorphism (Virtual Functions)

Base pointers can call derived overrides via virtual functions.

class Animal {
public:
    virtual void sound() { cout << "Generic\n"; }
    virtual ~Animal() = default;
};

class Dog : public Animal {
public:
    void sound() override { cout << "Bark\n"; }
};

Animal* a = new Dog();
a->sound(); // Bark
delete a;
      

5) Access Specifiers

public for API, private for internal state, protected for derived classes.

6) Composition (Has-a)

Build complex types by combining simpler ones.

class Engine {
public:
    void start() { cout << "Engine on\n"; }
};

class Car {
private:
    Engine engine;
public:
    void drive() { engine.start(); }
};
      

7) Common Pitfalls

  • Forgetting a virtual destructor in a base class.
  • Exposing data members publicly without need.
  • Copying large objects unintentionally (prefer references).
  • Overusing inheritance instead of composition.

STL (Standard Template Library)

STL provides reusable containers, iterators, and algorithms to write fast and expressive C++. Understanding complexity and usage patterns helps you choose the right tool.

1) Vector

Dynamic array with contiguous storage and amortized O(1) push back.

#include <vector>
vector<int> nums = {2, 4, 6};
nums.push_back(8);
for (int x : nums) cout << x << " ";
      

Reserve capacity to avoid reallocations when size is known.

vector<int> v;
v.reserve(100);
      

2) Array and Deque

array is fixed-size, deque supports fast push/pop at both ends.

#include <array>
#include <deque>

array<int, 3> a = {1, 2, 3};
deque<int> d;
d.push_front(1);
d.push_back(2);
      

3) List and Forward List

Linked lists allow fast insert/erase anywhere but no random access.

#include <list>
list<int> lst = {1, 2, 3};
auto it = lst.begin();
advance(it, 1);
lst.insert(it, 10);
      

4) Map and Unordered Map

Ordered map is a balanced tree (log n). Unordered map is a hash table (average O(1)).

#include <map>
#include <unordered_map>

map<string, int> scores;
scores["Rahul"] = 95;
scores["Asha"] = 88;

unordered_map<string, int> fastScores;
fastScores["Riya"] = 91;
      

5) Set and Unordered Set

Store unique values. Ordered set is sorted; unordered set is hashed.

#include <set>
#include <unordered_set>

set<int> s = {3, 1, 2};
unordered_set<int> us = {3, 1, 2};
      

6) Algorithms

Algorithms work with iterators; include <algorithm>.

#include <algorithm>

vector<int> nums2 = {5, 1, 9, 3};
sort(nums2.begin(), nums2.end());
auto itMax = max_element(nums2.begin(), nums2.end());
cout << *itMax << endl;
      

7) Iterators

Iterators are like pointers that allow generic traversal.

vector<int> data = {10, 20, 30};
for (auto it = data.begin(); it != data.end(); ++it) {
    cout << *it << " ";
}
      

8) Common Pitfalls

  • Invalidating iterators after erase/insert in some containers.
  • Assuming unordered_map preserves order.
  • Using list when random access is needed.
  • Forgetting to include the right header.

Dynamic Memory

Dynamic memory is allocated at runtime on the heap. It enables flexible data structures but requires careful management to avoid leaks, dangling pointers, and double frees.

1) Single Object Allocation

int* p = new int(25);
cout << *p << endl;
delete p;         // free single object
p = nullptr;      // avoid dangling pointer
      

2) Dynamic Arrays

Use new[] and delete[] for arrays.

int n = 5;
int* arr = new int[n];
for (int i = 0; i < n; i++) arr[i] = i * 10;
delete[] arr;
arr = nullptr;
      

3) Smart Pointers (Preferred)

Automatic memory management using RAII.

#include <memory>

auto up = std::make_unique<int>(42);
cout << *up << endl;

auto sp = std::make_shared<int>(99);
cout << *sp << endl;
      

4) Common Pitfalls

  • Memory leaks (forgetting to delete).
  • Using delete on memory allocated with new[].
  • Dangling pointers after freeing memory.
  • Double delete on the same pointer.

5) Best Practices

  • Prefer STL containers and smart pointers.
  • Set pointers to nullptr after delete.
  • Use RAII to manage resources safely.

File Handling

C++ file handling is done through stream classes in <fstream>. Use output streams to write and input streams to read. Always check if the file opened successfully.

1) Writing to a File

#include <fstream>

ofstream outFile("sample.txt");
if (!outFile) {
    cout << "Failed to open file for writing";
} else {
    outFile << "Hello from C++";
}
outFile.close();
      

2) Reading from a File

Use getline for line-by-line reading.

ifstream inFile("sample.txt");
if (!inFile) {
    cout << "Failed to open file for reading";
} else {
    string line;
    while (getline(inFile, line)) {
        cout << line << endl;
    }
}
inFile.close();
      

3) Appending to a File

ofstream logFile("sample.txt", ios::app);
logFile << "\nNew line added.";
logFile.close();
      

4) File Modes

Common modes include ios::in, ios::out, ios::app, ios::trunc, and ios::binary.

5) Binary File I/O

struct Data {
    int id;
    double score;
};

Data d = {1, 92.5};
ofstream binOut("data.bin", ios::binary);
binOut.write(reinterpret_cast<char*>(&d), sizeof(d));
binOut.close();

Data readD;
ifstream binIn("data.bin", ios::binary);
binIn.read(reinterpret_cast<char*>(&readD), sizeof(readD));
binIn.close();
      

6) Common Pitfalls

  • Not checking if the file opened successfully.
  • Mixing formatted and unformatted input without care.
  • Forgetting to close streams (use RAII or local scope).
  • Assuming text and binary behave the same across platforms.

Exception Handling

Exceptions provide a structured way to handle runtime errors without cluttering normal control flow. Use them for exceptional cases, not routine conditions.

1) Basic try / catch

try {
    int age = -1;
    if (age < 0) throw "Age cannot be negative";
}
catch (const char* msg) {
    cout << "Error: " << msg;
}
      

2) Throwing Standard Exceptions

Prefer exceptions from <stdexcept>.

#include <stdexcept>

int divide(int a, int b) {
    if (b == 0) throw std::invalid_argument("Divide by zero");
    return a / b;
}
      

3) Catching by Reference

Catching by const reference avoids slicing and copies.

try {
    throw std::runtime_error("Something went wrong");
}
catch (const std::exception& e) {
    cout << e.what() << endl;
}
      

4) Multiple catch Blocks

try {
    // risky code
}
catch (const std::invalid_argument& e) {
    cout << "Invalid: " << e.what();
}
catch (const std::exception& e) {
    cout << "Other error: " << e.what();
}
      

5) Custom Exceptions

Create your own exception types for clarity.

class NegativeAge : public std::exception {
public:
    const char* what() const noexcept override {
        return "Age cannot be negative";
    }
};
      

6) Best Practices

  • Throw exceptions for errors you cannot handle locally.
  • Use RAII to ensure resources are released when exceptions occur.
  • Avoid throwing raw pointers or C-strings.
  • Catch the most specific exception first.

Templates

Templates let you write generic, type-safe code. They are compiled per type, producing efficient, specialized implementations.

1) Function Template

template <typename T>
T maxValue(T a, T b) {
    return (a > b) ? a : b;
}

cout << maxValue(10, 20) << endl;
cout << maxValue(4.2, 2.8) << endl;
      

2) Class Template

template <typename T>
class Box {
public:
    Box(T v) : value(v) {}
    T get() const { return value; }
private:
    T value;
};

Box<int> bi(7);
Box<string> bs("Hi");
      

3) Template Specialization

Customize behavior for specific types.

template <typename T>
class Printer {
public:
    void print(T v) { cout << v; }
};

template <>
class Printer<bool> {
public:
    void print(bool v) { cout << (v ? "true" : "false"); }
};
      

4) Multiple Parameters

template <typename K, typename V>
class Pair {
public:
    Pair(K k, V v) : key(k), value(v) {}
    K key;
    V value;
};
      

5) Best Practices

  • Keep template code in header files.
  • Prefer typename for template parameters.
  • Use templates for generic logic, not every function.
  • Favor composition with STL containers over writing custom ones.

Modern C++ Features

Modern C++ (C++11 and later) focuses on safety, performance, and expressiveness. Below are widely used features you’ll see in real-world code.

1) auto and decltype

Let the compiler infer types to reduce verbosity.

auto x = 10;                 // int
auto y = 3.14;               // double
decltype(y) z = 2.71;        // same type as y
      

2) Range-Based for

vector<int> v = {1, 2, 3, 4};
for (int n : v) {
    cout << n << " ";
}
      

3) Lambda Expressions

Inline functions for algorithms and callbacks.

auto isEven = [](int x) { return x % 2 == 0; };
int countEven = count_if(v.begin(), v.end(), isEven);
      

4) Smart Pointers

Automatic memory management with RAII.

auto up = std::make_unique<int>(10);
auto sp = std::make_shared<int>(20);
      

5) Move Semantics

Efficiently transfer resources instead of copying.

string a = "Hello";
string b = std::move(a); // a is now empty/unspecified
      

6) nullptr and Uniform Initialization

int* p = nullptr;
vector<int> nums{1, 2, 3};
      

7) constexpr and noexcept

constexpr int square(int x) { return x * x; }
int square2(int x) noexcept { return x * x; }
      

8) Structured Bindings (C++17)

pair<int, string> info = {1, "Aman"};
auto [id, name] = info;
      

9) if with Initializer (C++17)

if (auto it = find(v.begin(), v.end(), 3); it != v.end()) {
    cout << "Found: " << *it;
}
      

10) Common Pitfalls

  • Overusing auto can hide intent for complex types.
  • Moving from objects you still need later.
  • Capturing variables in lambdas incorrectly (by reference vs value).