codingstuff.io
ExploreTutorialsProblemsCS Subjects
Get Started
ExploreTutorialsProblemsCS Subjects
Get Started
codingstuff.io

Master the art of building software through interactive tutorials, real-world problems, and guided projects.

Pune, Maharashtra, India

codingstuffmail@gmail.com

Product

  • Explore
  • Tutorials
  • Problems
  • CS Subjects

Company

  • About
  • Contact
  • Privacy Policy
  • Terms & Conditions
  • Sitemap

© 2026 codingstuff.io. All rights reserved.

Built with ❤️ for developers everywhere

/
/
All Tutorials
⚡

C++ Programming

55 / 87 topics
55C++11 Features56Preprocessors and Macros57Templates (Function & Class Templates)58Namespaces59File Handling, Buffers, istream & ostream60Exception Handling, Asserts & Debugging61Multithreading
Tutorials/C++ Programming/C++11 Features
⚡C++ Programming

C++11 Features

Updated 2026-05-12
30 min read

C++11 Features

In this tutorial, we will dive into several advanced features introduced in C++11 that have significantly enhanced the language's capabilities. These features include auto, nullptr, range-based for loops, move semantics, smart pointers, initializer lists, constexpr, and override/final. Understanding these concepts is crucial for writing modern, efficient, and maintainable C++ code.

Introduction

C++11 introduced a plethora of new features aimed at simplifying the language, improving performance, and making it more robust. These features not only make the code cleaner but also help in reducing errors and enhancing readability. In this tutorial, we will explore each of these features with examples to illustrate their usage.

Core Content

1. auto Keyword

The auto keyword allows the compiler to deduce the type of a variable from its initializer. This can make the code more concise and readable, especially when dealing with complex types.

auto_example.cpp
1#include <iostream>
2#include <vector>
3
4int main() {
5 auto i = 42; // int
6 auto d = 3.14; // double
7 auto v = std::vector<int>{1, 2, 3}; // std::vector<int>
8
9 for (auto elem : v) {
10 std::cout << elem << " ";
11 }
12 return 0;
13}
Output
1 2 3

Tip

Note: The auto keyword can sometimes make the code less readable if overused, so it's important to use it judiciously.

2. nullptr

The nullptr keyword was introduced as a safer alternative to using NULL (which is actually defined as 0). It provides better type safety and clarity.

nullptr_example.cpp
1#include <iostream>
2
3void foo(int x) {
4 std::cout << "Integer overload called." << std::endl;
5}
6
7void foo(void* ptr) {
8 std::cout << "Pointer overload called." << std::endl;
9}
10
11int main() {
12 int* ptr = nullptr;
13 foo(ptr); // Calls pointer overload
14 return 0;
15}
Output
Pointer overload called.

Warning

Do not use NULL in C++11 and beyond. Always use nullptr for better type safety.

3. Range-based For Loops

Range-based for loops provide a simpler syntax for iterating over elements in containers like arrays, vectors, or other iterable types.

range_based_for.cpp
1#include <iostream>
2#include <vector>
3
4int main() {
5 std::vector<int> v = {10, 20, 30};
6 for (auto elem : v) {
7 std::cout << elem << " ";
8 }
9 return 0;
10}
Output
10 20 30

Tip

Range-based for loops are particularly useful for iterating over containers without needing to manage iterators manually.

4. Move Semantics

Move semantics allow resources (like memory) to be transferred from one object to another, rather than copied. This can significantly improve performance by reducing unnecessary copying.

move_semantics.cpp
1#include <iostream>
2#include <vector>
3#include <string>
4
5class Resource {
6public:
7 Resource() { std::cout << "Resource acquired." << std::endl; }
8 ~Resource() { std::cout << "Resource released." << std::endl; }
9 Resource(const Resource&) { std::cout << "Resource copied." << std::endl; }
10 Resource(Resource&&) noexcept { std::cout << "Resource moved." << std::endl; }
11};
12
13int main() {
14 Resource r1;
15 Resource r2 = std::move(r1); // Move semantics
16 return 0;
17}
Output
Resource acquired.
Resource moved.
Resource released.

Tip

Move semantics are particularly useful when dealing with large objects or resources that are expensive to copy.

5. Smart Pointers

Smart pointers (std::unique_ptr, std::shared_ptr, and std::weak_ptr) provide automatic memory management, helping to prevent memory leaks and dangling pointers.

smart_pointers.cpp
1#include <iostream>
2#include <memory>
3
4class Resource {
5public:
6 Resource() { std::cout << "Resource acquired." << std::endl; }
7 ~Resource() { std::cout << "Resource released." << std::endl; }
8};
9
10int main() {
11 std::unique_ptr<Resource> ptr1 = std::make_unique<Resource>();
12 // std::unique_ptr<Resource> ptr2 = ptr1; // Error: unique_ptr cannot be copied
13 return 0;
14}
Output
Resource acquired.
Resource released.

Tip

Use std::unique_ptr when you want exclusive ownership of a resource. Use std::shared_ptr when multiple owners are needed, and use std::weak_ptr to break circular references.

6. Initializer Lists

Initializer lists allow for easy initialization of containers and other aggregate types.

initializer_lists.cpp
1#include <iostream>
2#include <vector>
3
4int main() {
5 std::vector<int> v = {1, 2, 3, 4, 5};
6 for (auto elem : v) {
7 std::cout << elem << " ";
8 }
9 return 0;
10}
Output
1 2 3 4 5

Tip

Initializer lists are a convenient way to initialize containers and other complex types.

7. constexpr

The constexpr specifier allows functions and variables to be evaluated at compile time, which can lead to performance improvements.

constexpr_example.cpp
1#include <iostream>
2
3constexpr int factorial(int n) {
4 return (n <= 1) ? 1 : (n * factorial(n - 1));
5}
6
7int main() {
8 constexpr int result = factorial(5); // Evaluated at compile time
9 std::cout << "Factorial of 5 is: " << result << std::endl;
10 return 0;
11}
Output
Factorial of 5 is: 120

Tip

constexpr functions and variables must have their arguments known at compile time, making them ideal for mathematical computations.

8. override and final

The override keyword ensures that a virtual function in a derived class correctly overrides a base class function. The final keyword prevents further overriding of a virtual function.

override_final.cpp
1#include <iostream>
2
3class Base {
4public:
5 virtual void foo() const { std::cout << "Base::foo()" << std::endl; }
6};
7
8class Derived : public Base {
9public:
10 void foo() const override { std::cout << "Derived::foo()" << std::endl; } // Correctly overrides Base::foo()
11};
12
13int main() {
14 Derived d;
15 d.foo();
16 return 0;
17}
Output
Derived::foo()

Tip

Using override helps catch errors related to function overriding, while final can be used to prevent further inheritance and modification of functions.

Practical Example

Let's put these features together in a practical example. We'll create a simple class that uses smart pointers, move semantics, and initializer lists.

practical_example.cpp
1#include <iostream>
2#include <vector>
3#include <memory>
4
5class Resource {
6public:
7 Resource() { std::cout << "Resource acquired." << std::endl; }
8 ~Resource() { std::cout << "Resource released." << std::endl; }
9 Resource(const Resource&) { std::cout << "Resource copied." << std::endl; }
10 Resource(Resource&&) noexcept { std::cout << "Resource moved." << std::endl; }
11};
12
13class Container {
14public:
15 Container(std::initializer_list<std::unique_ptr<Resource>> resources)
16 : resources_(resources) {}
17
18 void moveResources(Container& other) {
19 resources_ = std::move(other.resources_);
20 }
21
22private:
23 std::vector<std::unique_ptr<Resource>> resources_;
24};
25
26int main() {
27 Container c1({std::make_unique<Resource>(), std::make_unique<Resource>()});
28 Container c2;
29 c2.moveResources(c1);
30 return 0;
31}
Output
Resource acquired.
Resource acquired.
Resource moved.
Resource released.
Resource released.

Tip

This example demonstrates the use of smart pointers for automatic memory management, move semantics to efficiently transfer resources, and initializer lists for easy initialization.

Summary

FeatureDescription
autoAllows the compiler to deduce the type of a variable from its initializer.
nullptrProvides a safer alternative to NULL with better type safety.
Range-based ForSimplifies iteration over containers without managing iterators manually.
Move SemanticsEnables resource transfer instead of copying, improving performance.
Smart PointersProvide automatic memory management to prevent leaks and dangling pointers.
Initializer ListsAllow easy initialization of containers and other aggregate types.
constexprAllows functions and variables to be evaluated at compile time for efficiency.
override/finalEnsure correct function overriding and prevent further inheritance.

What's Next?

In the next tutorial, we will explore preprocessors and macros in C++. These tools provide powerful capabilities for text processing and code generation before compilation. Understanding preprocessors is essential for advanced programming techniques and optimizing your code.

Stay tuned for more insights into modern C++ programming!


PreviousAbstract Class and Pure Virtual FunctionNext Preprocessors and Macros

Recommended Gear

Abstract Class and Pure Virtual FunctionPreprocessors and Macros