C++ Modern Features
Overview
Modern C++ (C++11 and later) introduced many powerful features that make the language more expressive and safer.
auto Keyword (C++11)
Type Inference
cpp
#include <iostream>
#include <vector>
#include <map>
int main() {
// Auto type inference
auto x = 42; // int
auto y = 3.14; // double
auto name = "Hello"; // const char*
auto vec = std::vector<int>{1, 2, 3}; // std::vector<int>
// Auto with iterators
std::vector<int> numbers = {10, 20, 30};
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// Range-based for loop with auto
for (auto num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}Range-based for Loop (C++11)
cpp
#include <iostream>
#include <vector>
#include <map>
int main() {
// Vector iteration
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::cout << "Vector elements: ";
for (const auto& num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
// Map iteration
std::map<std::string, int> ages = {{"Alice", 25}, {"Bob", 30}};
std::cout << "Map elements:" << std::endl;
for (const auto& pair : ages) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
return 0;
}Lambda Expressions (C++11)
Basic Lambda Usage
cpp
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {5, 2, 8, 1, 9, 3};
// Sort using lambda
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a > b; // Sort in descending order
});
std::cout << "Sorted numbers: ";
for (int num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
// Find using lambda
auto it = std::find_if(numbers.begin(), numbers.end(), [](int x) {
return x > 5;
});
if (it != numbers.end()) {
std::cout << "First number > 5: " << *it << std::endl;
}
// Lambda with capture
int multiplier = 2;
auto multiply = [multiplier](int x) { return x * multiplier; };
std::cout << "5 * 2 = " << multiply(5) << std::endl;
return 0;
}Smart Pointers (C++11)
unique_ptr, shared_ptr, weak_ptr
cpp
#include <iostream>
#include <memory>
#include <vector>
class Resource {
public:
Resource() { std::cout << "Resource created" << std::endl; }
~Resource() { std::cout << "Resource destroyed" << std::endl; }
void doSomething() { std::cout << "Doing something" << std::endl; }
};
int main() {
// unique_ptr - exclusive ownership
{
std::unique_ptr<Resource> ptr1 = std::make_unique<Resource>();
ptr1->doSomething();
// Transfer ownership
std::unique_ptr<Resource> ptr2 = std::move(ptr1);
// ptr1 is now nullptr
if (!ptr1) {
std::cout << "ptr1 is null after move" << std::endl;
}
ptr2->doSomething();
} // Resource is automatically destroyed here
// shared_ptr - shared ownership
{
std::shared_ptr<Resource> shared1 = std::make_shared<Resource>();
std::cout << "Reference count: " << shared1.use_count() << std::endl;
{
std::shared_ptr<Resource> shared2 = shared1;
std::cout << "Reference count: " << shared1.use_count() << std::endl;
} // shared2 goes out of scope
std::cout << "Reference count: " << shared1.use_count() << std::endl;
} // Resource is destroyed when last shared_ptr goes out of scope
return 0;
}constexpr (C++11)
Compile-time Constants
cpp
#include <iostream>
// Compile-time function
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
// Compile-time variable
constexpr int MAX_SIZE = 100;
int main() {
constexpr int result = factorial(5); // Evaluated at compile time
std::cout << "Factorial of 5: " << result << std::endl;
std::cout << "MAX_SIZE: " << MAX_SIZE << std::endl;
// static_assert for compile-time checking
static_assert(factorial(5) == 120, "Factorial calculation error");
return 0;
}nullptr (C++11)
Null Pointer Literal
cpp
#include <iostream>
void process(int* ptr) {
if (ptr == nullptr) {
std::cout << "Null pointer" << std::endl;
} else {
std::cout << "Value: " << *ptr << std::endl;
}
}
int main() {
int value = 42;
process(&value); // Pass valid pointer
process(nullptr); // Pass null pointer
// Modern way to initialize pointers
int* ptr = nullptr; // Instead of NULL or 0
return 0;
}std::optional (C++17)
Optional Values
cpp
#include <iostream>
#include <optional>
#include <string>
std::optional<int> divide(int a, int b) {
if (b == 0) {
return std::nullopt; // No value
}
return a / b;
}
int main() {
auto result1 = divide(10, 2);
auto result2 = divide(10, 0);
if (result1) {
std::cout << "10 / 2 = " << *result1 << std::endl;
}
if (!result2) {
std::cout << "Division by zero - no result" << std::endl;
}
// Using value_or
int safe_result = result2.value_or(-1);
std::cout << "Safe result: " << safe_result << std::endl;
return 0;
}std::variant (C++17)
Type-safe Unions
cpp
#include <iostream>
#include <variant>
#include <string>
int main() {
std::variant<int, double, std::string> data;
data = 42;
std::cout << "Data holds int: " << std::get<int>(data) << std::endl;
data = 3.14;
std::cout << "Data holds double: " << std::get<double>(data) << std::endl;
data = "Hello";
std::cout << "Data holds string: " << std::get<std::string>(data) << std::endl;
// Using visitor
std::visit([](const auto& value) {
std::cout << "Visited value: " << value << std::endl;
}, data);
return 0;
}