1. C++的现代演进:从底层控制到高层抽象
C++这门语言总是让我想起瑞士军刀——它既能在底层硬件操作上游刃有余,又能构建复杂的抽象系统。从1998年标准化至今,C++已经走过了二十多年的现代化历程,特别是C++11带来的变革,彻底改变了我们编写C++代码的方式。作为一名长期奋战在一线的开发者,我见证了太多团队对C++的误解:有人把它当作"带类的C",有人则沉迷于过度设计。实际上,现代C++的精髓在于平衡——在性能与抽象、控制与安全、灵活与规范之间找到最佳实践。
2. C++的核心设计哲学解析
2.1 零开销抽象原则的工程意义
Bjarne Stroustrup提出的"零开销抽象"原则不是一句空话。在我的项目实践中,这个原则意味着:
cpp复制// 传统C风格
void process_data() {
int* buffer = (int*)malloc(1024 * sizeof(int));
// ...使用buffer...
free(buffer);
}
// 现代C++风格
void process_data() {
auto buffer = std::make_unique<int[]>(1024);
// ...使用buffer...
// 自动释放,异常安全
}
这两种写法在生成的机器代码上几乎相同,但后者提供了自动内存管理和异常安全。这就是零开销抽象的实际体现——你不必为使用高级特性而牺牲性能。
2.2 C++的分层使用模型
C++最强大的特性之一是它支持分层使用:
- C层:直接内存操作、指针运算
- OOP层:类、继承、多态
- 泛型层:模板、概念
- 函数式层:lambda、高阶函数
在嵌入式项目中,我可能主要使用C层;而在业务系统开发中,则更多依赖泛型和函数式特性。这种灵活性是其他语言难以企及的。
3. 现代内存管理实战
3.1 RAII模式的深入应用
RAII(Resource Acquisition Is Initialization)不仅是内存管理技术,更是资源管理的通用范式。我曾在一个网络服务项目中这样封装Socket资源:
cpp复制class Socket {
int fd;
public:
Socket(const std::string& host, int port) {
fd = ::socket(...);
if (fd == -1) throw std::runtime_error("...");
// 连接设置...
}
~Socket() {
if (fd != -1) ::close(fd);
}
// 禁用拷贝
Socket(const Socket&) = delete;
Socket& operator=(const Socket&) = delete;
// 允许移动
Socket(Socket&& other) noexcept : fd(other.fd) {
other.fd = -1;
}
// ...其他方法...
};
这种模式确保了资源在任何情况下(包括异常)都能正确释放。
3.2 智能指针的工程实践
智能指针的选择需要谨慎:
- unique_ptr:默认选择,零开销
- shared_ptr:共享所有权时使用
- weak_ptr:解决循环引用
实际项目中常见的误区是过度使用shared_ptr。我曾优化过一个性能瓶颈,发现是大量不必要的shared_ptr引用计数操作导致的。修改为unique_ptr配合明确的所有权转移后,性能提升了15%。
4. 类型系统与模板元编程
4.1 类型推断的最佳实践
auto关键字不是用来偷懒的,而是为了:
- 避免冗余类型声明
- 确保变量类型与初始化表达式严格一致
- 配合模板代码更易维护
cpp复制// 好例子
auto iter = container.find(key);
auto lock = std::unique_lock(mutex);
// 坏例子
auto result = ProcessData(); // 类型不明确
4.2 现代模板编程
C++20的concepts彻底改变了模板编程的游戏规则。在开发一个数学库时,我这样约束矩阵类型:
cpp复制template<typename T>
concept MatrixType = requires(T m, size_t i, size_t j) {
{ m.rows() } -> std::convertible_to<size_t>;
{ m.cols() } -> std::convertible_to<size_t>;
{ m(i,j) } -> std::floating_point;
};
template<MatrixType M>
auto computeNorm(const M& matrix) {
// 实现...
}
这种约束使错误信息更友好,代码更可读。
5. 并发编程实战
5.1 线程管理策略
直接使用std::thread通常不是最佳选择。现代C++项目更倾向于:
- 线程池模式
- 任务并行
- 异步I/O
一个基于C++17的简单线程池实现:
cpp复制class ThreadPool {
std::vector<std::thread> workers;
std::queue<std::function<void()>> tasks;
std::mutex queue_mutex;
std::condition_variable condition;
bool stop = false;
public:
ThreadPool(size_t threads) {
for(size_t i = 0; i < threads; ++i) {
workers.emplace_back([this] {
while(true) {
std::function<void()> task;
{
std::unique_lock lock(queue_mutex);
condition.wait(lock,
[this]{ return stop || !tasks.empty(); });
if(stop && tasks.empty()) return;
task = std::move(tasks.front());
tasks.pop();
}
task();
}
});
}
}
template<class F>
void enqueue(F&& f) {
{
std::unique_lock lock(queue_mutex);
tasks.emplace(std::forward<F>(f));
}
condition.notify_one();
}
~ThreadPool() {
{
std::unique_lock lock(queue_mutex);
stop = true;
}
condition.notify_all();
for(auto& worker : workers)
worker.join();
}
};
5.2 协程的实际应用
C++20协程在I/O密集型应用中表现出色。一个简单的HTTP请求协程示例:
cpp复制task<std::string> fetch_url(std::string url) {
auto executor = co_await this_coro::executor;
tcp::socket socket(executor);
auto endpoints = co_await resolver.async_resolve(
url.host(), "http", use_awaitable);
co_await async_connect(socket, endpoints, use_awaitable);
std::string request = fmt::format(
"GET {} HTTP/1.1\r\nHost: {}\r\n\r\n",
url.path(), url.host());
co_await async_write(socket, buffer(request), use_awaitable);
std::string response;
co_await async_read(socket, dynamic_buffer(response), use_awaitable);
co_return response;
}
6. 工程最佳实践
6.1 构建现代C++项目
现代C++项目应该具备:
- 模块化设计(C++20 Modules)
- 自动化构建系统(CMake)
- 静态分析工具集成
- 单元测试框架
- 持续集成流程
一个典型的CMake配置示例:
cmake复制cmake_minimum_required(VERSION 3.15)
project(ModernCpp LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_library(core
src/core/utils.cpp
src/core/network.cpp
)
target_include_directories(core PUBLIC include)
target_compile_options(core PRIVATE -Wall -Wextra -Wpedantic)
add_executable(main_app src/main.cpp)
target_link_libraries(main_app PRIVATE core)
6.2 调试与优化技巧
- AddressSanitizer:检测内存错误
- ThreadSanitizer:检测数据竞争
- UBSan:检测未定义行为
- perf:性能分析
启动ASan的方式:
bash复制clang++ -fsanitize=address -fno-omit-frame-pointer -g program.cpp
7. C++与其他语言的交互
7.1 C++与Java的互操作
通过JNI实现C++与Java交互的典型模式:
cpp复制#include <jni.h>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_NativeLib_getMessage(JNIEnv* env, jobject /* this */) {
std::string message = "Hello from C++";
return env->NewStringUTF(message.c_str());
}
对应的Java代码:
java复制public class NativeLib {
static {
System.loadLibrary("nativelib");
}
public native String getMessage();
}
7.2 Web服务中的C++应用
使用C++构建高性能Web服务的常见选择:
- REST API:cpprestsdk、Drogon
- gRPC:Google的高性能RPC框架
- WebAssembly:将C++编译为WASM在浏览器运行
一个简单的cpprestsdk示例:
cpp复制int main() {
web::http::experimental::listener::http_listener listener(
"http://localhost:8080/api");
listener.support(web::http::methods::GET,
[](web::http::http_request request) {
auto response = web::json::value::object();
response["message"] = web::json::value::string("Hello");
request.reply(web::http::status_codes::OK, response);
});
try {
listener.open().wait();
std::cout << "Listening...\n";
std::cin.get();
listener.close().wait();
} catch(const std::exception& e) {
std::cerr << "Error: " << e.what() << "\n";
}
return 0;
}
8. 性能优化实战
8.1 缓存友好的设计
现代CPU的缓存体系对性能影响巨大。一个矩阵乘法的优化案例:
cpp复制// 低效版本(缓存不友好)
void multiply(const Matrix& a, const Matrix& b, Matrix& result) {
for(size_t i = 0; i < a.rows(); ++i) {
for(size_t k = 0; k < a.cols(); ++k) {
for(size_t j = 0; j < b.cols(); ++j) {
result(i,j) += a(i,k) * b(k,j);
}
}
}
}
// 优化版本(缓存友好)
void multiply_optimized(const Matrix& a, const Matrix& b, Matrix& result) {
constexpr size_t block = 64 / sizeof(double); // 假设double类型
for(size_t i = 0; i < a.rows(); i += block) {
for(size_t j = 0; j < b.cols(); j += block) {
for(size_t k = 0; k < a.cols(); k += block) {
// 处理block x block的子矩阵
for(size_t ii = i; ii < std::min(i+block, a.rows()); ++ii) {
for(size_t kk = k; kk < std::min(k+block, a.cols()); ++kk) {
for(size_t jj = j; jj < std::min(j+block, b.cols()); ++jj) {
result(ii,jj) += a(ii,kk) * b(kk,jj);
}
}
}
}
}
}
}
这种分块处理可以显著提升缓存命中率,在我的测试中带来了3-5倍的性能提升。
8.2 SIMD向量化优化
现代CPU的SIMD指令集(SSE, AVX等)可以并行处理多个数据:
cpp复制#include <immintrin.h>
void vector_add(const float* a, const float* b, float* c, size_t n) {
size_t i = 0;
for(; i + 8 <= n; i += 8) {
__m256 va = _mm256_loadu_ps(a + i);
__m256 vb = _mm256_loadu_ps(b + i);
__m256 vc = _mm256_add_ps(va, vb);
_mm256_storeu_ps(c + i, vc);
}
// 处理剩余元素
for(; i < n; ++i) {
c[i] = a[i] + b[i];
}
}
在实际项目中,结合编译器自动向量化(-O3 -mavx2)和手动优化,可以获得最佳效果。
9. 现代C++的未来方向
9.1 模块化编程
C++20引入的模块(Modules)将改变传统的头文件包含模式:
cpp复制// math.ixx
export module math;
export namespace math {
int add(int a, int b) {
return a + b;
}
}
// main.cpp
import math;
int main() {
return math::add(1, 2);
}
模块化带来的好处包括:
- 更快的编译速度
- 更好的隔离性
- 更清晰的接口定义
9.2 编译期编程的演进
C++23将进一步增强编译期能力,包括:
- constexpr标准库扩展
- 编译期反射
- 更强大的模板元编程
一个编译期字符串处理的例子:
cpp复制constexpr std::string_view trim(std::string_view str) {
while(!str.empty() && std::isspace(str.front())) {
str.remove_prefix(1);
}
while(!str.empty() && std::isspace(str.back())) {
str.remove_suffix(1);
}
return str;
}
static_assert(trim(" hello ") == "hello");
这种能力使得越来越多的逻辑可以在编译期完成,减少运行时开销。
10. 跨平台开发实践
10.1 可移植代码编写技巧
编写跨平台C++代码需要注意:
- 使用标准库而非平台特定API
- 谨慎处理字节序和数据类型大小
- 抽象系统差异
一个文件系统操作的跨平台封装:
cpp复制std::string get_config_path() {
#ifdef _WIN32
char buf[MAX_PATH];
GetModuleFileNameA(NULL, buf, MAX_PATH);
return std::filesystem::path(buf).parent_path() / "config.ini";
#else
return "/etc/app/config.conf";
#endif
}
10.2 条件编译的最佳实践
避免过度使用#ifdef:
cpp复制// 不好的做法
#ifdef LINUX
// Linux特定代码
#else
// Windows代码
#endif
// 更好的做法
class PlatformInterface {
public:
virtual void do_something() = 0;
virtual ~PlatformInterface() = default;
};
std::unique_ptr<PlatformInterface> create_platform_interface();
这种设计模式使得平台相关代码被隔离在特定实现文件中。
11. 大型项目架构经验
11.1 组件化设计
在参与一个百万行级C++项目时,我们采用了这样的组件结构:
- 核心库:基础工具、算法
- 业务模块:独立功能单元
- 接口层:模块间通信
- 插件系统:动态扩展
每个组件都有:
- 清晰的接口定义
- 独立的测试套件
- 版本兼容性保证
11.2 依赖管理策略
现代C++项目的依赖管理选择:
- 源码集成:子模块或直接包含
- 包管理器:vcpkg、conan
- 系统包:apt、brew
使用vcpkg的示例:
bash复制vcpkg install fmt boost-asio
CMake集成:
cmake复制find_package(fmt REQUIRED)
find_package(Boost REQUIRED COMPONENTS asio)
target_link_libraries(my_app PRIVATE fmt::fmt Boost::asio)
12. 测试与质量保证
12.1 单元测试框架比较
常用C++测试框架:
- Google Test:功能全面
- Catch2:简单易用
- doctest:编译速度快
Google Test示例:
cpp复制#include <gtest/gtest.h>
TEST(MathTest, Addition) {
EXPECT_EQ(2, 1 + 1);
}
TEST(MathTest, Subtraction) {
EXPECT_GT(3, 2);
}
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
12.2 性能测试方法
使用Google Benchmark进行性能测试:
cpp复制#include <benchmark/benchmark.h>
static void BM_StringCreation(benchmark::State& state) {
for (auto _ : state) {
std::string empty_string;
benchmark::DoNotOptimize(empty_string);
}
}
BENCHMARK(BM_StringCreation);
static void BM_StringCopy(benchmark::State& state) {
std::string x = "hello";
for (auto _ : state) {
std::string copy(x);
benchmark::DoNotOptimize(copy);
}
}
BENCHMARK(BM_StringCopy);
BENCHMARK_MAIN();
13. 异常处理与错误管理
13.1 现代错误处理策略
C++错误处理的最佳实践:
- 异常用于不可恢复错误
- 返回错误码用于预期错误
- std::optional/std::expected用于可能失败的操作
使用std::expected(C++23)的例子:
cpp复制std::expected<int, std::string> parse_number(std::string_view str) {
try {
return std::stoi(std::string(str));
} catch(const std::exception& e) {
return std::unexpected("parse failed");
}
}
void process() {
if(auto num = parse_number("123")) {
std::cout << *num << "\n";
} else {
std::cerr << num.error() << "\n";
}
}
13.2 异常安全保证
C++中的异常安全级别:
- 基本保证:资源不泄漏,对象处于有效状态
- 强保证:操作要么完全成功,要么状态回滚
- 不��保证:操作不会抛出异常
实现强保证的典型模式:
cpp复制class Database {
struct Impl;
std::unique_ptr<Impl> pimpl;
public:
void update(const Record& rec) {
auto new_impl = std::make_unique<Impl>(*pimpl); // 拷贝
new_impl->apply_update(rec); // 可能抛出
pimpl = std::move(new_impl); // 不抛出
}
};
14. C++与其他语言的对比
14.1 C++与Java的设计哲学差异
关键区别:
- 内存管理:手动 vs 自动GC
- 运行时:零开销 vs JVM
- 泛型:编译期 vs 类型擦除
- 性能:可预测 vs JIT优化
在需要低延迟的场景下,C++的确定性内存管理往往更胜一筹。
14.2 何时选择C++而非其他语言
适合C++的场景:
- 需要极致性能
- 需要直接硬件访问
- 资源受限环境
- 已有大量C++代码基础
不适合C++的场景:
- 快速原型开发
- 简单业务逻辑
- 团队缺乏C++经验
15. 学习资源与进阶路径
15.1 推荐学习路线
-
基础阶段:
- 《C++ Primer》
- 《Effective C++》
- 掌握STL容器和算法
-
进阶阶段:
- 《Effective Modern C++》
- 《C++ Concurrency in Action》
- 深入模板和泛型编程
-
专家阶段:
- 《C++ Templates: The Complete Guide》
- 参与开源项目
- 研究标准提案和编译器实现
15.2 实用工具链
开发工具推荐:
- 编译器:Clang、GCC、MSVC
- 构建系统:CMake、Bazel
- IDE:CLion、VS、Qt Creator
- 调试器:GDB、LLDB、WinDbg
- 分析工具:perf、VTune、Hotspot
16. 实际项目经验分享
16.1 高性能交易系统案例
在一个高频交易系统项目中,我们通过以下C++技术实现了微秒级延迟:
- 自定义内存分配器
- 无锁数据结构
- 内核旁路网络
- SIMD指令优化
- 精细的缓存控制
关键优化点:
cpp复制// 自定义无锁队列
template<typename T>
class LockFreeQueue {
struct Node {
std::atomic<Node*> next;
T value;
};
std::atomic<Node*> head;
std::atomic<Node*> tail;
public:
void push(T value) {
Node* node = new Node{nullptr, std::move(value)};
Node* prev = tail.exchange(node, std::memory_order_acq_rel);
prev->next.store(node, std::memory_order_release);
}
bool pop(T& value) {
Node* old_head = head.load(std::memory_order_relaxed);
Node* next = old_head->next.load(std::memory_order_acquire);
if(next == nullptr) return false;
value = std::move(next->value);
head.store(next, std::memory_order_release);
delete old_head;
return true;
}
};
16.2 游戏引擎开发经验
在3D游戏引擎开发中,现代C++特性的应用:
- ECS架构与模板元编程
- 资源管理的智能指针策略
- 多线程渲染管线
- SIMD数学库
- 基于协程的任务系统
一个简单的组件定义:
cpp复制template<typename... Components>
class View {
entt::registry& registry;
public:
View(entt::registry& reg) : registry(reg) {}
template<typename Func>
void each(Func func) {
auto view = registry.view<Components...>();
for(auto entity : view) {
func(entity, view.template get<Components>(entity)...);
}
}
};
// 使用示例
entt::registry registry;
View<Transform, RigidBody> physics_view(registry);
physics_view.each([](auto entity, Transform& t, RigidBody& rb) {
// 物理更新逻辑
});
17. 模板元编程深度应用
17.1 SFINAE与标签分发
现代C++中SFINAE的典型应用:
cpp复制template<typename T>
auto serialize(const T& obj) -> decltype(obj.serialize(), std::string()) {
return obj.serialize();
}
template<typename T>
auto serialize(const T& obj) -> decltype(to_string(obj), std::string()) {
return to_string(obj);
}
template<typename T>
auto serialize(const T& obj) -> decltype(std::to_string(obj), std::string()) {
return std::to_string(obj);
}
std::string serialize(...) {
static_assert(false, "No serialization method available");
}
17.2 编译期类型反射
C++20后更简洁的实现方式:
cpp复制template<typename T>
concept HasSerialize = requires(const T& t) {
{ t.serialize() } -> std::convertible_to<std::string>;
};
template<typename T>
concept HasToString = requires(const T& t) {
{ to_string(t) } -> std::convertible_to<std::string>;
};
template<typename T>
std::string serialize(const T& obj) {
if constexpr (HasSerialize<T>) {
return obj.serialize();
} else if constexpr (HasToString<T>) {
return to_string(obj);
} else if constexpr (std::integral<T> || std::floating_point<T>) {
return std::to_string(obj);
} else {
static_assert(false, "Type not serializable");
}
}
18. 移动语义与完美转发
18.1 右值引用的实际应用
移动语义的正确使用:
cpp复制class Buffer {
size_t size_;
std::unique_ptr<uint8_t[]> data_;
public:
// 移动构造函数
Buffer(Buffer&& other) noexcept
: size_(other.size_), data_(std::move(other.data_)) {
other.size_ = 0;
}
// 移动赋值运算符
Buffer& operator=(Buffer&& other) noexcept {
if(this != &other) {
size_ = other.size_;
data_ = std::move(other.data_);
other.size_ = 0;
}
return *this;
}
// 禁用拷贝
Buffer(const Buffer&) = delete;
Buffer& operator=(const Buffer&) = delete;
};
18.2 完美转发模式
通用引用和完美转发的典型应用:
cpp复制class ThreadPool {
public:
template<typename F, typename... Args>
auto enqueue(F&& f, Args&&... args) {
using ReturnType = std::invoke_result_t<F, Args...>;
auto task = std::make_shared<std::packaged_task<ReturnType()>>(
std::bind(std::forward<F>(f), std::forward<Args>(args)...));
std::future<ReturnType> res = task->get_future();
{
std::unique_lock lock(queue_mutex_);
tasks_.emplace([task](){ (*task)(); });
}
condition_.notify_one();
return res;
}
};
19. 标准库深度使用
19.1 容器选择策略
标准库容器的性能特点:
- vector:连续内存,快速随机访问
- deque:分块连续,快速头尾操作
- list:双向链表,快速插入删除
- map/set:红黑树,有序存储
- unordered_map/set:哈希表,快速查找
选择容器的决策树:
- 需要快速查找?→ unordered_map/unordered_set
- 需要有序?→ map/set
- 需要频繁头尾操作?→ deque
- 需要频繁中间插入?→ list
- 默认选择→ vector
19.2 算法组合技巧
STL算法的强大组合能力:
cpp复制// 统计满足条件的元素数量
auto count = std::count_if(vec.begin(), vec.end(), [](auto& x) {
return x > 0;
});
// 转换并过滤
std::vector<int> result;
std::ranges::copy(
vec | std::views::transform([](auto x) { return x * 2; })
| std::views::filter([](auto x) { return x % 3 == 0; }),
std::back_inserter(result));
// 并行排序
std::sort(std::execution::par, vec.begin(), vec.end());
20. 嵌入式C++开发
20.1 资源受限环境优化
嵌入式C++的特殊考量:
- 禁用异常(-fno-exceptions)
- 禁用RTTI(-fno-rtti)
- 自定义内存管理
- 静态分配优先
一个嵌入式系统的内存池实现:
cpp复制template<typename T, size_t N>
class StaticPool {
std::array<std::aligned_storage_t<sizeof(T), alignof(T)>, N> storage;
std::bitset<N> used;
public:
template<typename... Args>
T* allocate(Args&&... args) {
for(size_t i = 0; i < N; ++i) {
if(!used[i]) {
used[i] = true;
return new(&storage[i]) T(std::forward<Args>(args)...);
}
}
return nullptr;
}
void deallocate(T* obj) {
for(size_t i = 0; i < N; ++i) {
if(&storage[i] == reinterpret_cast<char*>(obj)) {
obj->~T();
used[i] = false;
return;
}
}
}
};
20.2 硬件寄存器访问
安全访问硬件寄存器模式:
cpp复制template<typename T>
class Register {
volatile T* reg;
public:
explicit Register(uintptr_t addr) : reg(reinterpret_cast<volatile T*>(addr)) {}
void write(T value) { *reg = value; }
T read() const { return *reg; }
void set_bits(T mask) { *reg |= mask; }
void clear_bits(T mask) { *reg &= ~mask; }
void toggle_bits(T mask) { *reg ^= mask; }
Register& operator=(T value) { write(value); return *this; }
operator T() const { return read(); }
};
// 使用示例
Register<uint32_t> status_reg(0x40021000);
status_reg.set_bits(0x1); // 设置第0位
if(status_reg & 0x2) { // 检查第1位
// ...
}
21. 元编程与代码生成
21.1 编译期字符串处理
利用constexpr实现编译期字符串操作:
cpp复制template<size_t N>
struct FixedString {
char str[N]{};
constexpr FixedString(const char (&s)[N]) {
std::copy_n(s, N, str);
}
constexpr bool operator==(const FixedString& other) const {
return std::equal(str, str + N, other.str);
}
template<size_t M>
constexpr auto operator+(const FixedString<M>& other) const {
FixedString<N + M - 1> result{};
std::copy_n(str, N - 1, result.str);
std::copy_n(other.str, M, result.str + N - 1);
return result;
}
};
template<FixedString S>
constexpr auto operator""_fs() {
return S;
}
constexpr auto hello = "Hello"_fs;
constexpr auto world = "World"_fs;
constexpr auto hello_world = hello + " "_fs + world;
static_assert(hello_world == "Hello World"_fs);
21.2 代码生成工具链
现代C++项目常用的代码生成工具:
- Protobuf:协议编解码
- FlatBuffers:高效序列化
- Lex/Yacc:语法分析
- CMake配置生成:自动化构建
一个使用Protobuf的示例:
protobuf复制syntax = "proto3";
message Person {
string name = 1;
int32 id = 2;
repeated string emails = 3;
}
生成的C++代码提供了高效的序列化接口:
cpp复制Person person;
person.set_name("John Doe");
person.set_id(1234);
person.add_emails("john@example.com");
std::string serialized;
person.SerializeToString(&serialized);
22. 调试与诊断技巧
22.1 自定义断言宏
增强版的断言实现:
cpp复制#define ASSERT(cond) \
do { \
if(!(cond)) { \
std::cerr << "Assertion failed: " #cond \
<< ", file " << __FILE__ \
<< ", line " << __LINE__ \
<< ", function " << __func__ << "\n"; \
std::abort(); \
} \
} while(false)
#define ASSERT_MSG(cond, msg) \
do { \
if(!(cond)) { \
std::cerr << "Assertion failed: " #cond \
<< "\nMessage: " << msg \
<< "\nFile: " << __FILE__ \
<< "\nLine: " << __LINE__ \
<< "\nFunction: " << __func__ << "\n"; \
std::abort(); \
} \
} while(false)
22.2 栈回溯与核心分析
Linux环境下捕获调用栈:
cpp复制#include <execinfo.h>
#include <unistd.h>
void print_stacktrace() {
void* buffer[100];
int nptrs = backtrace(buffer, 100);
char** strings = backtrace_symbols(buffer, nptrs);
if(strings) {
for(int i = 0; i < nptrs; ++i) {
std::cerr << strings[i] << "\n";
}
free(strings);
}
}
void signal_handler(int sig) {
std::cerr << "Received signal " << sig << "\n";
print_stacktrace();
_exit(1);
}
void setup_signal_handlers() {
signal(SIGSEGV, signal_handler);
signal(SIGABRT, signal_handler);
signal(SIGILL, signal_handler);
}
23. 多范式编程实践
23.1 函数式风格应用
现代C++支持多种函数式编程特性:
cpp复制// 高阶函数
auto compose(auto f, auto g) {
return [=](auto x) { return f(g(x)); };
}
// 柯里化
auto curry(auto f) {
return [=](auto x) {
return [=](auto y) {
return f(x, y);
};
};
}
// 使用示例
auto add = [](auto x, auto y) { return x + y; };
auto curried_add = curry(add);
auto add_five = curried_add(5);
std::cout << add_five(3); // 输出8
23.2 面向切面编程
使用模板实现AOP风格编程:
cpp复制template<typename F>
auto log_time(F f) {
return [f](auto&&... args) {
auto start = std::chrono::high_resolution_clock::now();
auto result = f(std::forward<decltype(args)>(args)...);
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms\n";
return result;
};
}
// 使用示例
auto slow_func = []() {
std::this_thread::sleep_for(std::chrono::seconds(1));
return 42;
};
auto logged_func = log_time(slow_func);
auto result = logged_func(); // 输出执行时间
24. 设计模式现代实现
24.1 策略模式新写法
利用std::function和lambda的现代实现:
cpp复制class Processor {
std::function<void(const std::string&)> strategy_;
public:
explicit Processor(std::function<void(const std::string&)> strategy)
: strategy_(std::move(strategy)) {}
void process(const std::string& data) {
strategy_(data);
}
};
// 使用示例
Processor p1([](const std::string& s) {
std::cout << "Default: " << s << "\n";
});
Processor p2([](const std::string& s) {
std::cout << "Uppercase: " << to_upper(s) << "\n";
});
p1.process("hello"); // 输出: Default: hello
p2.process("hello"); // 输出: Uppercase: HELLO
24.2 观察者模式改进
使用信号槽机制的现代实现:
cpp复制template<typename... Args>
class Signal {
std::vector<std::function<void(Args...)>> slots_;
public:
void connect(std::function<void(Args...)> slot) {
slots_.push_back(std::move(slot));
}
void emit(Args... args) {
for(auto& slot : slots_) {
slot(args...);
}
}
