- name
- cpp
- description
- Modern C++ programming patterns and idioms
- domain
- programming-languages
- version
- 1.0.0
- tags
- ["cpp","c++","stl","raii","templates","memory"]
- triggers
- {"keywords":{"primary":["cpp","c++","cmake","stl","template","raii"],"secondary":["smart pointer","move","constexpr","lambda","boost","qt"]},"context_boost":["systems","performance","embedded","game","graphics"],"context_penalty":["python","javascript","java","web"],"priority":"high"}
# C++
## Overview
Modern C++ (C++11 and beyond) patterns including RAII, smart pointers, templates, and STL.
---
## Modern C++ Fundamentals
### Smart Pointers
```cpp
#include <memory>
#include <iostream>
// unique_ptr - exclusive ownership
class Resource {
public:
Resource() { std::cout << "Resource acquired\n"; }
~Resource() { std::cout << "Resource released\n"; }
void use() { std::cout << "Resource used\n"; }
};
void unique_ptr_example() {
// Create unique_ptr
auto ptr = std::make_unique<Resource>();
ptr->use();
// Transfer ownership
auto ptr2 = std::move(ptr);
// ptr is now nullptr
// Array support
auto arr = std::make_unique<int[]>(10);
}
// shared_ptr - shared ownership
void shared_ptr_example() {
auto shared1 = std::make_shared<Resource>();
{
auto shared2 = shared1; // Reference count = 2
shared2->use();
} // shared2 destroyed, count = 1
std::cout << "Use count: " << shared1.use_count() << "\n";
} // shared1 destroyed, resource released
// weak_ptr - non-owning reference
class Node {
public:
std::shared_ptr<Node> next;
std::weak_ptr<Node> prev; // Avoid circular reference
~Node() { std::cout << "Node destroyed\n"; }
};
void weak_ptr_example() {
auto node1 = std::make_shared<Node>();
auto node2 = std::make_shared<Node>();
node1->next = node2;
node2->prev = node1; // weak_ptr, no ownership
if (auto locked = node2->prev.lock()) {
// Use locked (shared_ptr)
}
}
```
### RAII Pattern
```cpp
#include <fstream>
#include <mutex>
// File wrapper with RAII
class File {
std::fstream file_;
public:
explicit File(const std::string& filename)
: file_(filename, std::ios::in | std::ios::out) {
if (!file_.is_open()) {
throw std::runtime_error("Failed to open file");
}
}
~File() {
if (file_.is_open()) {
file_.close();
}
}
// Delete copy operations
File(const File&) = delete;
File& operator=(const File&) = delete;
// Allow move operations
File(File&& other) noexcept : file_(std::move(other.file_)) {}
File& operator=(File&& other) noexcept {
file_ = std::move(other.file_);
return *this;
}
void write(const std::string& data) {
file_ << data;
}
};
// Lock guard (RAII for mutex)
class ThreadSafeCounter {
mutable std::mutex mutex_;
int count_ = 0;
public:
void increment() {
std::lock_guard<std::mutex> lock(mutex_);
++count_;
}
int get() const {
std::lock_guard<std::mutex> lock(mutex_);
return count_;
}
};
// Scoped cleanup
template<typename F>
class ScopeGuard {
F cleanup_;
bool active_ = true;
public:
explicit ScopeGuard(F cleanup) : cleanup_(std::move(cleanup)) {}
~ScopeGuard() {
if (active_) cleanup_();
}
void dismiss() { active_ = false; }
ScopeGuard(const ScopeGuard&) = delete;
ScopeGuard& operator=(const ScopeGuard&) = delete;
};
// Usage
void example() {
auto resource = acquireResource();
ScopeGuard guard([&]() { releaseResource(resource); });
// Do work...
guard.dismiss(); // Don't cleanup if successful
}
```
### Move Semantics
```cpp
#include <vector>
#include <string>
#include <utility>
class Buffer {
std::unique_ptr<char[]> data_;
size_t size_;
public:
// Constructor
explicit Buffer(size_t size) : data_(new char[size]), size_(size) {}
// Copy constructor
Buffer(const Buffer& other) : data_(new char[other.size_]), size_(other.size_) {
std::copy(other.data_.get(), other.data_.get() + size_, data_.get());
}
// Move constructor
Buffer(Buffer&& other) noexcept
: data_(std::move(other.data_)), size_(other.size_) {
other.size_ = 0;
}
// Copy assignment
Buffer& operator=(const Buffer& other) {
if (this != &other) {
data_.reset(new char[other.size_]);
size_ = other.size_;
std::copy(other.data_.get(), other.data_.get() + size_, data_.get());
}
return *this;
}
// Move assignment
Buffer& operator=(Buffer&& other) noexcept {
if (this != &other) {
data_ = std::move(other.data_);
size_ = other.size_;
other.size_ = 0;
}
return *this;
}
size_t size() const { return size_; }
};
// Perfect forwarding
template<typename T, typename... Args>
std::unique_ptr<T> make_unique_custom(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
```
---
## Templates
### Function Templates
```cpp
#include <type_traits>
#include <concepts>
// Basic template
template<typename T>
T max(T a, T b) {
return (a > b) ? a : b;
}
// Template specialization
template<>
const char* max<const char*>(const char* a, const char* b) {
return (strcmp(a, b) > 0) ? a : b;
}
// SFINAE (Substitution Failure Is Not An Error)
template<typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
double_value(T value) {
return value * 2;
}
// C++20 Concepts
template<typename T>
concept Numeric = std::is_arithmetic_v<T>;
template<Numeric T>
T add(T a, T b) {
return a + b;
}
// Requires clause
template<typename T>
requires std::is_default_constructible_v<T>
T create_default() {
return T{};
}
// Variadic templates
template<typename... Args>
void print(Args... args) {
(std::cout << ... << args) << "\n";
}
// Fold expressions
template<typename... Args>
auto sum(Args... args) {
return (args + ...);
}
```
### Class Templates
```cpp
// Generic container
template<typename T, size_t N>
class Array {
T data_[N];
public:
constexpr size_t size() const { return N; }
T& operator[](size_t index) {
if (index >= N) throw std::out_of_range("Index out of range");
return data_[index];
}
const T& operator[](size_t index) const {
if (index >= N) throw std::out_of_range("Index out of range");
return data_[index];
}
T* begin() { return data_; }
T* end() { return data_ + N; }
const T* begin() const { return data_; }
const T* end() const { return data_ + N; }
};
// Template with default arguments
template<typename T, typename Allocator = std::allocator<T>>
class Vector {
// ...
};
// Partial specialization
template<typename T>
class Container<T*> {
// Specialization for pointer types
};
// CRTP (Curiously Recurring Template Pattern)
template<typename Derived>
class Counter {
static inline int count_ = 0;
public:
Counter() { ++count_; }
~Counter() { --count_; }
static int count() { return count_; }
};
class Widget : public Counter<Widget> {
// Widget inherits counting behavior
};
```
---
## STL Containers and Algorithms
```cpp
#include <vector>
#include <map>
#include <unordered_map>
#include <set>
#include <algorithm>
#include <numeric>
void container_examples() {
// vector
std::vector<int> vec{1, 2, 3, 4, 5};
vec.push_back(6);
vec.emplace_back(7); // Construct in place
// map
std::map<std::string, int> ordered_map;
ordered_map["one"] = 1;
ordered_map.insert({"two", 2});
ordered_map.try_emplace("three", 3);
// unordered_map
std::unordered_map<std::string, int> hash_map;
hash_map["one"] = 1;
// set
std::set<int> ordered_set{3, 1, 4, 1, 5};
auto [iter, inserted] = ordered_set.insert(9);
}
void algorithm_examples() {
std::vector<int> vec{5, 2, 8, 1, 9, 3};
// Sort
std::sort(vec.begin(), vec.end());
std::sort(vec.begin(), vec.end(), std::greater<int>());
// Find
auto it = std::find(vec.begin(), vec.end(), 8);
auto it2 = std::find_if(vec.begin(), vec.end(), [](int n) { return n > 5; });
// Transform
std::vector<int> doubled(vec.size());
std::transform(vec.begin(), vec.end(), doubled.begin(), [](int n) { return n * 2; });
// Accumulate
int sum = std::accumulate(vec.begin(), vec.end(), 0);
// Remove-erase idiom
vec.erase(std::remove_if(vec.begin(), vec.end(), [](int n) { return n < 3; }), vec.end());
// C++20 ranges (simplified)
// auto result = vec | std::views::filter([](int n) { return n > 3; })
// | std::views::transform([](int n) { return n * 2; });
}
```
---
## Concurrency
```cpp
#include <thread>
#include <future>
#include <mutex>
#include <condition_variable>
#include <atomic>
// Basic threading
void thread_example() {
std::thread t([]() {
std::cout << "Hello from thread\n";
});
Voir sur GitHub