乐闻世界logo
搜索文章和话题

C++面试题手册

C++ 智能指针如何使用

C++ 智能指针深度解析智能指针是 C++11 引入的重要特性,用于自动管理动态分配的内存,避免内存泄漏和悬空指针问题。智能指针概述为什么需要智能指针?自动释放内存,避免内存泄漏防止悬空指针和双重释放提供异常安全的内存管理明确表达所有权语义RAII 原则:资源获取即初始化(Resource Acquisition Is Initialization)资源在构造函数中获取,在析构函数中释放利用对象生命周期管理资源unique_ptr基本用法:#include <memory>// 创建 unique_ptrstd::unique_ptr<int> ptr1(new int(42));std::unique_ptr<int> ptr2 = std::make_unique<int>(42); // C++14// 访问对象*ptr1 = 100;std::cout << *ptr1 << std::endl;// 重置ptr1.reset(); // 释放内存ptr1.reset(new int(200)); // 重新分配// 释放所有权int* rawPtr = ptr1.release(); // ptr1 不再管理内存delete rawPtr; // 手动删除// 检查是否为空if (ptr1) { std::cout << "ptr1 is not empty" << std::endl;}移动语义:// unique_ptr 只能移动,不能拷贝std::unique_ptr<int> ptr1 = std::make_unique<int>(42);std::unique_ptr<int> ptr2 = std::move(ptr1); // 移动构造// ptr1 现在为空if (!ptr1) { std::cout << "ptr1 is empty after move" << std::endl;}// 移动赋值std::unique_ptr<int> ptr3;ptr3 = std::move(ptr2); // ptr2 变为空自定义删除器:// 数组删除器struct ArrayDeleter { void operator()(int* p) const { delete[] p; }};std::unique_ptr<int, ArrayDeleter> arr(new int[10]);// 使用 lambda 删除器auto deleter = [](FILE* f) { fclose(f); };std::unique_ptr<FILE, decltype(deleter)> file(fopen("test.txt", "w"), deleter);// 使用默认数组删除器std::unique_ptr<int[]> arr2(new int[10]);arr2[0] = 1;arr2[1] = 2;在容器中使用:std::vector<std::unique_ptr<int>> vec;// 使用 make_uniquevec.push_back(std::make_unique<int>(1));vec.push_back(std::make_unique<int>(2));// 使用 emplace_backvec.emplace_back(std::make_unique<int>(3));// 遍历for (const auto& ptr : vec) { std::cout << *ptr << std::endl;}shared_ptr基本用法:// 创建 shared_ptrstd::shared_ptr<int> ptr1(new int(42));std::shared_ptr<int> ptr2 = std::make_shared<int>(42); // 推荐// 拷贝构造std::shared_ptr<int> ptr3 = ptr1; // 引用计数 +1// 赋值std::shared_ptr<int> ptr4;ptr4 = ptr1; // 引用计数 +1// 查看引用计数std::cout << "use_count: " << ptr1.use_count() << std::endl;// 重置ptr1.reset(); // 引用计数 -1引用计数机制:class MyClass {public: MyClass() { std::cout << "Constructor" << std::endl; } ~MyClass() { std::cout << "Destructor" << std::endl; }};{ std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(); std::cout << "Count: " << ptr1.use_count() << std::endl; // 1 { std::shared_ptr<MyClass> ptr2 = ptr1; std::cout << "Count: " << ptr1.use_count() << std::endl; // 2 } std::cout << "Count: " << ptr1.use_count() << std::endl; // 1} // ptr1 析构,对象被删除自定义删除器:// 使用函数指针void customDeleter(int* p) { std::cout << "Custom deleter called" << std::endl; delete p;}std::shared_ptr<int> ptr(new int(42), customDeleter);// 使用 lambdaauto deleter = [](int* p) { std::cout << "Lambda deleter called" << std::endl; delete p;};std::shared_ptr<int> ptr2(new int(42), deleter);// 数组删除器std::shared_ptr<int> arr(new int[10], [](int* p) { delete[] p;});get() 和 reset():std::shared_ptr<int> ptr = std::make_shared<int>(42);// 获取原始指针int* rawPtr = ptr.get();*rawPtr = 100;// 重置ptr.reset(); // 释放当前对象ptr.reset(new int(200)); // 管理新对象weak_ptr基本用法:// 创建 weak_ptrstd::shared_ptr<int> shared = std::make_shared<int>(42);std::weak_ptr<int> weak = shared;// 检查是否过期if (!weak.expired()) { std::cout << "Object still exists" << std::endl;}// 锁定获取 shared_ptrif (auto ptr = weak.lock()) { std::cout << *ptr << std::endl;}解决循环引用:class Node {public: std::shared_ptr<Node> next; std::weak_ptr<Node> prev; // 使用 weak_ptr 避免循环引用 ~Node() { std::cout << "Node destroyed" << std::endl; }};void createCycle() { auto node1 = std::make_shared<Node>(); auto node2 = std::make_shared<Node>(); node1->next = node2; node2->prev = node1; // weak_ptr 不会增加引用计数 // node1 和 node2 会被正确释放}观察者模式:class Subject {private: std::vector<std::weak_ptr<Observer>> observers;public: void addObserver(std::shared_ptr<Observer> obs) { observers.push_back(obs); } void notify() { for (auto it = observers.begin(); it != observers.end(); ) { if (auto obs = it->lock()) { obs->update(); ++it; } else { // 观察者已被删除,移除 it = observers.erase(it); } } }};智能指针最佳实践1. 优先使用 makeunique 和 makeshared// 推荐auto ptr1 = std::make_unique<int>(42);auto ptr2 = std::make_shared<int>(42);// 不推荐std::unique_ptr<int> ptr1(new int(42));std::shared_ptr<int> ptr2(new int(42));2. 避免使用裸指针管理智能指针// 不推荐int* raw = new int(42);std::unique_ptr<int> ptr(raw);// 推荐auto ptr = std::make_unique<int>(42);3. 不要从函数返回裸指针// 不推荐int* getPtr() { auto ptr = std::make_unique<int>(42); return ptr.get(); // 危险!}// 推荐std::shared_ptr<int> getPtr() { return std::make_shared<int>(42);}4. 使用智能指针管理数组// unique_ptr 数组std::unique_ptr<int[]> arr(new int[10]);arr[0] = 1;// shared_ptr 数组(需要自定义删除器)std::shared_ptr<int> arr(new int[10], [](int* p) { delete[] p; });5. 在函数参数中使用智能指针// 按值传递(增加引用计数)void process(std::shared_ptr<int> ptr) { // 使用 ptr}// 按引用传递(不增加引用计数)void process(const std::shared_ptr<int>& ptr) { // 使用 ptr}// 传递裸指针(如果函数不需要所有权)void process(int* ptr) { // 使用 ptr}常见陷阱1. 循环引用class A {public: std::shared_ptr<B> b;};class B {public: std::shared_ptr<A> a; // 循环引用!};// 解决:使用 weak_ptrclass B {public: std::weak_ptr<A> a; // 正确};2. this 指针问题class MyClass {public: std::shared_ptr<MyClass> getShared() { return shared_from_this(); // 需要 enable_shared_from_this }};class MyClass : public std::enable_shared_from_this<MyClass> { // ...};3. 混合使用裸指针和智能指针std::shared_ptr<int> ptr = std::make_shared<int>(42);int* raw = ptr.get();delete raw; // 错误!会导致双重释放4. 在构造函数中传递 thisclass MyClass {public: MyClass() { // 错误!此时对象还未完全构造 registerObserver(this); }};// 解决:使用两阶段构造class MyClass {public: static std::shared_ptr<MyClass> create() { auto ptr = std::shared_ptr<MyClass>(new MyClass()); ptr->init(); return ptr; }private: MyClass() = default; void init() { registerObserver(shared_from_this()); }};性能考虑1. shared_ptr 的开销引用计数:两个原子整数(控制块)内存分配:控制块和对象可能分开分配线程安全:引用计数操作是原子的2. make_shared 的优势一次内存分配:对象和控制块一起分配更好的缓存局部性减少内存碎片3. weak_ptr 的开销需要额外的弱引用计数lock() 操作需要原子操作实际应用场景1. 工厂模式class Factory {public: template <typename T, typename... Args> static std::shared_ptr<T> create(Args&&... args) { return std::make_shared<T>(std::forward<Args>(args)...); }};auto obj = Factory::create<MyClass>(arg1, arg2);2. 依赖注入class Service {public: Service(std::shared_ptr<Database> db) : db_(db) {} void execute() { db_->query("SELECT * FROM table"); }private: std::shared_ptr<Database> db_;};3. 资源管理class ResourceManager {public: void addResource(std::unique_ptr<Resource> resource) { resources_.push_back(std::move(resource)); } Resource* getResource(size_t index) { return resources_[index].get(); }private: std::vector<std::unique_ptr<Resource>> resources_;};注意事项智能指针不能管理栈对象避免在循环中创建大量 shared_ptr注意智能指针的线程安全性在多线程环境中使用 shared_ptr 时要注意引用计数的原子操作考虑使用自定义分配器优化性能理解智能指针的所有权语义,选择合适的类型
阅读 0·2月18日 17:41

C++ 网络编程基础如何实现

C++ 网络编程基础C++ 网络编程是构建高性能网络应用的基础,涉及套接字编程、协议实现和并发处理等核心概念。套接字基础TCP 套接字示例:#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <cstring>class TCPServer {private: int serverSocket; int port; bool running;public: TCPServer(int p) : port(p), running(false) { serverSocket = socket(AF_INET, SOCK_STREAM, 0); if (serverSocket < 0) { throw std::runtime_error("Failed to create socket"); } // 设置地址重用 int opt = 1; setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); } void start() { struct sockaddr_in serverAddr; memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = INADDR_ANY; serverAddr.sin_port = htons(port); if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { throw std::runtime_error("Failed to bind socket"); } if (listen(serverSocket, 5) < 0) { throw std::runtime_error("Failed to listen on socket"); } running = true; std::cout << "Server listening on port " << port << std::endl; while (running) { struct sockaddr_in clientAddr; socklen_t clientLen = sizeof(clientAddr); int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientLen); if (clientSocket < 0) { if (running) { std::cerr << "Failed to accept connection" << std::endl; } continue; } char clientIP[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, INET_ADDRSTRLEN); std::cout << "Client connected: " << clientIP << std::endl; handleClient(clientSocket); } } void stop() { running = false; close(serverSocket); }private: void handleClient(int clientSocket) { char buffer[1024]; while (true) { ssize_t bytesRead = recv(clientSocket, buffer, sizeof(buffer) - 1, 0); if (bytesRead <= 0) { break; } buffer[bytesRead] = '\0'; std::cout << "Received: " << buffer << std::endl; // 发送响应 const char* response = "Message received"; send(clientSocket, response, strlen(response), 0); } close(clientSocket); }};// 使用int main() { try { TCPServer server(8080); server.start(); } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0;}UDP 套接字示例:class UDPServer {private: int serverSocket; int port;public: UDPServer(int p) : port(p) { serverSocket = socket(AF_INET, SOCK_DGRAM, 0); if (serverSocket < 0) { throw std::runtime_error("Failed to create UDP socket"); } struct sockaddr_in serverAddr; memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = INADDR_ANY; serverAddr.sin_port = htons(port); if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { throw std::runtime_error("Failed to bind UDP socket"); } } void receive() { char buffer[1024]; struct sockaddr_in clientAddr; socklen_t clientLen = sizeof(clientAddr); while (true) { ssize_t bytesRead = recvfrom(serverSocket, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&clientAddr, &clientLen); if (bytesRead < 0) { std::cerr << "Failed to receive data" << std::endl; continue; } buffer[bytesRead] = '\0'; char clientIP[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, INET_ADDRSTRLEN); std::cout << "Received from " << clientIP << ": " << buffer << std::endl; // 发送响应 const char* response = "UDP Response"; sendto(serverSocket, response, strlen(response), 0, (struct sockaddr*)&clientAddr, clientLen); } } ~UDPServer() { close(serverSocket); }};非阻塞 I/O设置非阻塞套接字:#include <fcntl.h>void setNonBlocking(int socket) { int flags = fcntl(socket, F_GETFL, 0); if (flags < 0) { throw std::runtime_error("Failed to get socket flags"); } if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) < 0) { throw std::runtime_error("Failed to set non-blocking mode"); }}// 使用int sock = socket(AF_INET, SOCK_STREAM, 0);setNonBlocking(sock);使用 select 进行多路复用:#include <sys/select.h>class SelectServer {private: int serverSocket; int maxFd; fd_set readFds;public: SelectServer(int port) { serverSocket = socket(AF_INET, SOCK_STREAM, 0); setNonBlocking(serverSocket); struct sockaddr_in serverAddr; memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = INADDR_ANY; serverAddr.sin_port = htons(port); bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)); listen(serverSocket, 5); maxFd = serverSocket; FD_ZERO(&readFds); FD_SET(serverSocket, &readFds); } void run() { while (true) { fd_set tempFds = readFds; int activity = select(maxFd + 1, &tempFds, nullptr, nullptr, nullptr); if (activity < 0) { std::cerr << "Select error" << std::endl; continue; } // 检查新连接 if (FD_ISSET(serverSocket, &tempFds)) { handleNewConnection(); } // 检查现有连接 for (int fd = 0; fd <= maxFd; ++fd) { if (fd != serverSocket && FD_ISSET(fd, &tempFds)) { handleClientData(fd); } } } }private: void handleNewConnection() { struct sockaddr_in clientAddr; socklen_t clientLen = sizeof(clientAddr); int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientLen); if (clientSocket < 0) { return; } setNonBlocking(clientSocket); FD_SET(clientSocket, &readFds); if (clientSocket > maxFd) { maxFd = clientSocket; } } void handleClientData(int fd) { char buffer[1024]; ssize_t bytesRead = recv(fd, buffer, sizeof(buffer) - 1, 0); if (bytesRead <= 0) { close(fd); FD_CLR(fd, &readFds); return; } buffer[bytesRead] = '\0'; std::cout << "Received: " << buffer << std::endl; }};epoll 高性能 I/Oepoll 服务器示例:#include <sys/epoll.h>class EpollServer {private: int serverSocket; int epollFd; static constexpr int MAX_EVENTS = 64;public: EpollServer(int port) { serverSocket = socket(AF_INET, SOCK_STREAM, 0); setNonBlocking(serverSocket); struct sockaddr_in serverAddr; memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = INADDR_ANY; serverAddr.sin_port = htons(port); bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)); listen(serverSocket, 5); epollFd = epoll_create1(0); if (epollFd < 0) { throw std::runtime_error("Failed to create epoll instance"); } struct epoll_event event; event.events = EPOLLIN | EPOLLET; // 边缘触发 event.data.fd = serverSocket; if (epoll_ctl(epollFd, EPOLL_CTL_ADD, serverSocket, &event) < 0) { throw std::runtime_error("Failed to add socket to epoll"); } } void run() { struct epoll_event events[MAX_EVENTS]; while (true) { int numEvents = epoll_wait(epollFd, events, MAX_EVENTS, -1); if (numEvents < 0) { std::cerr << "Epoll wait error" << std::endl; continue; } for (int i = 0; i < numEvents; ++i) { if (events[i].data.fd == serverSocket) { handleNewConnection(); } else { handleClientData(events[i].data.fd); } } } }private: void handleNewConnection() { struct sockaddr_in clientAddr; socklen_t clientLen = sizeof(clientAddr); int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientLen); if (clientSocket < 0) { return; } setNonBlocking(clientSocket); struct epoll_event event; event.events = EPOLLIN | EPOLLET; event.data.fd = clientSocket; epoll_ctl(epollFd, EPOLL_CTL_ADD, clientSocket, &event); } void handleClientData(int fd) { char buffer[1024]; ssize_t bytesRead = recv(fd, buffer, sizeof(buffer) - 1, 0); if (bytesRead <= 0) { epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, nullptr); close(fd); return; } buffer[bytesRead] = '\0'; std::cout << "Received: " << buffer << std::endl; const char* response = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!"; send(fd, response, strlen(response), 0); } ~EpollServer() { close(serverSocket); close(epollFd); }};HTTP 服务器实现简单的 HTTP 服务器:class HTTPServer {private: int serverSocket;public: HTTPServer(int port) { serverSocket = socket(AF_INET, SOCK_STREAM, 0); int opt = 1; setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); struct sockaddr_in serverAddr; memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = INADDR_ANY; serverAddr.sin_port = htons(port); bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)); listen(serverSocket, 5); } void run() { while (true) { struct sockaddr_in clientAddr; socklen_t clientLen = sizeof(clientAddr); int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientLen); if (clientSocket < 0) { continue; } handleRequest(clientSocket); close(clientSocket); } }private: void handleRequest(int clientSocket) { char buffer[4096]; ssize_t bytesRead = recv(clientSocket, buffer, sizeof(buffer) - 1, 0); if (bytesRead > 0) { buffer[bytesRead] = '\0'; std::cout << "Request:\n" << buffer << std::endl; // 解析 HTTP 请求 std::string request(buffer); std::string response = generateResponse(request); send(clientSocket, response.c_str(), response.length(), 0); } } std::string generateResponse(const std::string& request) { std::string response = "HTTP/1.1 200 OK\r\n"; response += "Content-Type: text/html\r\n"; response += "Connection: close\r\n"; std::string body = "<html><body><h1>Hello, World!</h1></body></html>"; response += "Content-Length: " + std::to_string(body.length()) + "\r\n"; response += "\r\n"; response += body; return response; }};最佳实践1. 使用 RAII 管理套接字class Socket {private: int fd;public: Socket(int domain, int type, int protocol) { fd = socket(domain, type, protocol); if (fd < 0) { throw std::runtime_error("Failed to create socket"); } } ~Socket() { if (fd >= 0) { close(fd); } } int getFd() const { return fd; } // 禁止拷贝 Socket(const Socket&) = delete; Socket& operator=(const Socket&) = delete; // 允许移动 Socket(Socket&& other) noexcept : fd(other.fd) { other.fd = -1; }};2. 错误处理void checkError(int result, const std::string& message) { if (result < 0) { throw std::runtime_error(message + ": " + strerror(errno)); }}// 使用int sock = socket(AF_INET, SOCK_STREAM, 0);checkError(sock, "Failed to create socket");3. 超时设置void setSocketTimeout(int socket, int seconds) { struct timeval timeout; timeout.tv_sec = seconds; timeout.tv_usec = 0; setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));}4. 使用线程池处理连接class ThreadPoolServer {private: TCPServer server; ThreadPool pool;public: ThreadPoolServer(int port, size_t threadCount) : server(port), pool(threadCount) {} void run() { server.setOnClientHandler([this](int clientSocket) { pool.enqueue([clientSocket]() { handleClient(clientSocket); }); }); server.start(); }};注意事项始终检查系统调用的返回值处理部分读写的情况注意字节序转换(htons, ntohs 等)考虑使用更高级的网络库(如 Boost.Asio)在多线程环境中注意线程安全处理信号中断(EINTR)考虑使用 TLS/SSL 加密通信注意资源泄漏,确保套接字正确关闭
阅读 0·2月18日 17:39

C++ 性能优化技巧有哪些

C++ 性能优化技巧C++ 以其高性能著称,但要充分发挥其性能潜力,需要掌握各种优化技巧和最佳实践。编译器优化编译选项:# 基本优化g++ -O2 program.cpp -o program# 最高级别优化g++ -O3 program.cpp -o program# 链接时优化(LTO)g++ -O3 -flto program.cpp -o program# 针对特定架构优化g++ -O3 -march=native program.cpp -o program# 启用向量化g++ -O3 -ftree-vectorize program.cpp -o program内联函数:// 显式内联inline int add(int a, int b) { return a + b;}// 编译器自动内联(小函数)int multiply(int a, int b) { return a * b;}// 强制内联(GCC/Clang)__attribute__((always_inline)) int divide(int a, int b) { return a / b;}// 禁止内联__attribute__((noinline)) void heavyFunction() { // 复杂计算}内存优化数据局部性:// 不推荐:缓存不友好struct BadLayout { int a; char padding1[64]; // 浪费缓存行 int b; char padding2[64]; int c;};// 推荐:缓存友好struct GoodLayout { int a, b, c; // 紧凑排列};// 数组访问模式void processArray(int* arr, size_t size) { // 推荐:顺序访问 for (size_t i = 0; i < size; ++i) { process(arr[i]); } // 不推荐:随机访问 for (size_t i = 0; i < size; ++i) { process(arr[randomIndex()]); }}内存对齐:// 使用 alignas 指定对齐struct alignas(64) AlignedData { int data[16];};// 使用 aligned_alloc 分配对齐内存void* alignedMemory = aligned_alloc(64, 1024);// 查询对齐要求constexpr size_t alignment = alignof(double);避免内存碎片:// 推荐:对象池template <typename T, size_t PoolSize>class ObjectPool {private: std::array<T, PoolSize> pool; std::bitset<PoolSize> used;public: T* allocate() { size_t index = used.find_first_not_set(); if (index != std::string::npos) { used.set(index); return &pool[index]; } return nullptr; } void deallocate(T* ptr) { size_t index = ptr - pool.data(); used.reset(index); }};算法优化避免不必要的拷贝:// 不推荐:返回值拷贝std::vector<int> createVector() { std::vector<int> temp; // 填充数据 return temp; // C++11 之前会拷贝}// 推荐:移动语义std::vector<int> createVector() { std::vector<int> temp; // 填充数据 return temp; // C++11 之后会移动}// 使用移动语义std::vector<int> vec = createVector(); // 移动构造使用引用传递:// 不推荐:值传递void process(std::vector<int> data) { // 处理数据}// 推荐:const 引用传递void process(const std::vector<int>& data) { // 处理数据}// 需要修改时使用引用void modify(std::vector<int>& data) { // 修改数据}选择合适的容器:// 需要随机访问:vectorstd::vector<int> vec;// 需要频繁两端插入:dequestd::deque<int> dq;// 需要频繁中间插入删除:liststd::list<int> lst;// 需要按键查找:map/unordered_mapstd::map<std::string, int> mp;std::unordered_map<std::string, int> ump;// 需要快速查找:set/unordered_setstd::set<int> s;std::unordered_set<int> us;并发优化使用线程池:class ThreadPool {private: std::vector<std::thread> workers; std::queue<std::function<void()>> tasks; std::mutex queueMutex; std::condition_variable condition; bool stop;public: ThreadPool(size_t threads) : stop(false) { for (size_t i = 0; i < threads; ++i) { workers.emplace_back([this] { while (true) { std::function<void()> task; { std::unique_lock<std::mutex> lock(queueMutex); condition.wait(lock, [this] { return stop || !tasks.empty(); }); if (stop && tasks.empty()) return; task = std::move(tasks.front()); tasks.pop(); } task(); } }); } } template <class F, class... Args> auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> { using return_type = typename std::result_of<F(Args...)>::type; auto task = std::make_shared<std::packaged_task<return_type()>>( std::bind(std::forward<F>(f), std::forward<Args>(args)...) ); std::future<return_type> res = task->get_future(); { std::unique_lock<std::mutex> lock(queueMutex); if (stop) throw std::runtime_error("enqueue on stopped ThreadPool"); tasks.emplace([task]() { (*task)(); }); } condition.notify_one(); return res; } ~ThreadPool() { { std::unique_lock<std::mutex> lock(queueMutex); stop = true; } condition.notify_all(); for (auto& worker : workers) { worker.join(); } }};使用原子操作:// 不推荐:使用互斥锁std::mutex mtx;int counter = 0;void increment() { std::lock_guard<std::mutex> lock(mtx); ++counter;}// 推荐:使用原子操作std::atomic<int> counter(0);void increment() { counter.fetch_add(1, std::memory_order_relaxed);}减少锁竞争:// 不推荐:全局锁std::mutex globalMutex;std::map<int, int> globalMap;// 推荐:分段锁class ShardedMap {private: static constexpr size_t NUM_SHARDS = 16; std::array<std::mutex, NUM_SHARDS> mutexes; std::array<std::map<int, int>, NUM_SHARDS> maps; size_t getShard(int key) { return key % NUM_SHARDS; }public: void insert(int key, int value) { size_t shard = getShard(key); std::lock_guard<std::mutex> lock(mutexes[shard]); maps[shard][key] = value; } bool find(int key, int& value) { size_t shard = getShard(key); std::lock_guard<std::mutex> lock(mutexes[shard]); auto it = maps[shard].find(key); if (it != maps[shard].end()) { value = it->second; return true; } return false; }};SIMD 优化使用编译器内置函数:#include <immintrin.h>void addArrays(float* a, float* b, float* result, size_t size) { size_t i = 0; // 使用 AVX2 处理 8 个 float for (; i + 8 <= size; i += 8) { __m256 va = _mm256_loadu_ps(&a[i]); __m256 vb = _mm256_loadu_ps(&b[i]); __m256 vr = _mm256_add_ps(va, vb); _mm256_storeu_ps(&result[i], vr); } // 处理剩余元素 for (; i < size; ++i) { result[i] = a[i] + b[i]; }}使用自动向量化:// 编译器会自动向量化void addArrays(float* __restrict__ a, float* __restrict__ b, float* __restrict__ result, size_t size) { #pragma omp simd for (size_t i = 0; i < size; ++i) { result[i] = a[i] + b[i]; }}缓存优化预取数据:#include <xmmintrin.h>void processArray(int* arr, size_t size) { for (size_t i = 0; i < size; ++i) { // 预取下一个缓存行 if (i + 16 < size) { _mm_prefetch(&arr[i + 16], _MM_HINT_T0); } process(arr[i]); }}缓存行对齐:// 避免伪共享struct alignas(64) Counter { std::atomic<int> value; char padding[64 - sizeof(std::atomic<int>)];};class SharedCounters {private: Counter counters[4];public: void increment(int threadId) { counters[threadId % 4].value.fetch_add(1); }};性能分析使用性能分析工具:# 使用 perf(Linux)perf record -g ./your_programperf report# 使用 gprofg++ -pg program.cpp -o program./programgprof program gmon.out > analysis.txt# 使用 Valgrind 的 callgrindvalgrind --tool=callgrind ./your_programkcachegrind callgrind.out.<pid>使用计时器:#include <chrono>class Timer {private: std::chrono::high_resolution_clock::time_point start;public: Timer() : start(std::chrono::high_resolution_clock::now()) {} double elapsed() const { auto end = std::chrono::high_resolution_clock::now(); return std::chrono::duration<double>(end - start).count(); }};// 使用Timer timer;// 执行代码std::cout << "Elapsed time: " << timer.elapsed() << " seconds" << std::endl;最佳实践1. 预分配内存// 推荐std::vector<int> vec;vec.reserve(10000); // 预先分配空间// 不推荐std::vector<int> vec;for (int i = 0; i < 10000; ++i) { vec.push_back(i); // 多次重新分配}2. 使用 emplace 代替 push// 推荐vec.emplace_back(arg1, arg2); // 原地构造// 不推荐vec.push_back(Type(arg1, arg2)); // 可能创建临时对象3. 避免过早优化// 先写清晰的代码int sum = 0;for (int val : data) { sum += val;}// 性能分析后再优化if (isPerformanceCritical) { // 使用 SIMD 或并行化}4. 使用 constexpr 进行编译期计算// 推荐constexpr int factorial(int n) { return n <= 1 ? 1 : n * factorial(n - 1);}constexpr int result = factorial(10); // 编译期计算5. 避免虚函数调用开销// 性能关键代码避免虚函数class FastProcessor {public: void process(int value) { // 非虚函数 // 快速处理 }};// 使用 CRTP 实现静态多态template <typename Derived>class Base {public: void interface() { static_cast<Derived*>(this)->implementation(); }};注意事项性能优化应该基于实际测量,而非猜测优先优化算法和数据结构,而非微优化考虑可读性和可维护性,不要过度优化使用性能分析工具找出真正的瓶颈注意不同编译器和平台的优化差异考虑使用现代 C++ 特性(如移动语义)提升性能在多线程环境中注意缓存一致性和内存屏障
阅读 0·2月18日 17:38

C++ 设计模式如何实现

C++ 设计模式设计模式是软件设计中常见问题的可重用解决方案,C++ 作为一门强大的面向对象语言,非常适合实现各种设计模式。创建型模式单例模式(Singleton):class Singleton {private: static Singleton* instance; Singleton() = default; ~Singleton() = default;public: Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; static Singleton& getInstance() { static Singleton instance; return instance; } void doSomething() { std::cout << "Singleton doing something" << std::endl; }};// 使用Singleton& singleton = Singleton::getInstance();singleton.doSomething();工厂模式(Factory):// 抽象产品class Product {public: virtual ~Product() = default; virtual void operation() = 0;};// 具体产品class ConcreteProductA : public Product {public: void operation() override { std::cout << "Product A operation" << std::endl; }};class ConcreteProductB : public Product {public: void operation() override { std::cout << "Product B operation" << std::endl; }};// 抽象工厂class Factory {public: virtual ~Factory() = default; virtual std::unique_ptr<Product> createProduct() = 0;};// 具体工厂class FactoryA : public Factory {public: std::unique_ptr<Product> createProduct() override { return std::make_unique<ConcreteProductA>(); }};class FactoryB : public Factory {public: std::unique_ptr<Product> createProduct() override { return std::make_unique<ConcreteProductB>(); }};// 使用std::unique_ptr<Factory> factory = std::make_unique<FactoryA>();auto product = factory->createProduct();product->operation();建造者模式(Builder):class Computer {private: std::string cpu; std::string gpu; int ram;public: void setCPU(const std::string& cpu) { this->cpu = cpu; } void setGPU(const std::string& gpu) { this->gpu = gpu; } void setRAM(int ram) { this->ram = ram; } void show() { std::cout << "CPU: " << cpu << ", GPU: " << gpu << ", RAM: " << ram << "GB" << std::endl; }};class ComputerBuilder {private: Computer computer;public: ComputerBuilder& setCPU(const std::string& cpu) { computer.setCPU(cpu); return *this; } ComputerBuilder& setGPU(const std::string& gpu) { computer.setGPU(gpu); return *this; } ComputerBuilder& setRAM(int ram) { computer.setRAM(ram); return *this; } Computer build() { return computer; }};// 使用Computer computer = ComputerBuilder() .setCPU("Intel i9") .setGPU("NVIDIA RTX 4090") .setRAM(32) .build();computer.show();结构型模式适配器模式(Adapter):// 目标接口class Target {public: virtual ~Target() = default; virtual void request() = 0;};// 被适配者class Adaptee {public: void specificRequest() { std::cout << "Adaptee specific request" << std::endl; }};// 适配器class Adapter : public Target {private: std::unique_ptr<Adaptee> adaptee;public: Adapter() : adaptee(std::make_unique<Adaptee>()) {} void request() override { adaptee->specificRequest(); }};// 使用std::unique_ptr<Target> target = std::make_unique<Adapter>();target->request();装饰器模式(Decorator):// 组件接口class Component {public: virtual ~Component() = default; virtual void operation() = 0;};// 具体组件class ConcreteComponent : public Component {public: void operation() override { std::cout << "ConcreteComponent operation" << std::endl; }};// 装饰器基类class Decorator : public Component {private: std::unique_ptr<Component> component;public: Decorator(std::unique_ptr<Component> comp) : component(std::move(comp)) {} void operation() override { component->operation(); }};// 具体装饰器class ConcreteDecoratorA : public Decorator {public: ConcreteDecoratorA(std::unique_ptr<Component> comp) : Decorator(std::move(comp)) {} void operation() override { Decorator::operation(); addedBehavior(); } void addedBehavior() { std::cout << "Added behavior A" << std::endl; }};// 使用std::unique_ptr<Component> component = std::make_unique<ConcreteComponent>();component = std::make_unique<ConcreteDecoratorA>(std::move(component));component->operation();外观模式(Facade):class SubsystemA {public: void operationA() { std::cout << "Subsystem A operation" << std::endl; }};class SubsystemB {public: void operationB() { std::cout << "Subsystem B operation" << std::endl; }};class SubsystemC {public: void operationC() { std::cout << "Subsystem C operation" << std::endl; }};// 外观class Facade {private: std::unique_ptr<SubsystemA> subsystemA; std::unique_ptr<SubsystemB> subsystemB; std::unique_ptr<SubsystemC> subsystemC;public: Facade() : subsystemA(std::make_unique<SubsystemA>()), subsystemB(std::make_unique<SubsystemB>()), subsystemC(std::make_unique<SubsystemC>()) {} void operation() { subsystemA->operationA(); subsystemB->operationB(); subsystemC->operationC(); }};// 使用Facade facade;facade.operation();行为型模式观察者模式(Observer):#include <vector>#include <functional>// 观察者接口class Observer {public: virtual ~Observer() = default; virtual void update(const std::string& message) = 0;};// 主题class Subject {private: std::vector<std::reference_wrapper<Observer>> observers;public: void attach(Observer& observer) { observers.push_back(observer); } void detach(Observer& observer) { observers.erase( std::remove_if(observers.begin(), observers.end(), [&observer](auto& obs) { return &obs.get() == &observer; }), observers.end()); } void notify(const std::string& message) { for (auto& observer : observers) { observer.get().update(message); } }};// 具体观察者class ConcreteObserver : public Observer {private: std::string name;public: ConcreteObserver(const std::string& n) : name(n) {} void update(const std::string& message) override { std::cout << name << " received: " << message << std::endl; }};// 使用Subject subject;ConcreteObserver observer1("Observer 1");ConcreteObserver observer2("Observer 2");subject.attach(observer1);subject.attach(observer2);subject.notify("Hello observers!");策略模式(Strategy):// 策略接口class Strategy {public: virtual ~Strategy() = default; virtual int execute(int a, int b) = 0;};// 具体策略class AddStrategy : public Strategy {public: int execute(int a, int b) override { return a + b; }};class MultiplyStrategy : public Strategy {public: int execute(int a, int b) override { return a * b; }};// 上下文class Context {private: std::unique_ptr<Strategy> strategy;public: void setStrategy(std::unique_ptr<Strategy> s) { strategy = std::move(s); } int executeStrategy(int a, int b) { return strategy->execute(a, b); }};// 使用Context context;context.setStrategy(std::make_unique<AddStrategy>());std::cout << context.executeStrategy(10, 20) << std::endl;context.setStrategy(std::make_unique<MultiplyStrategy>());std::cout << context.executeStrategy(10, 20) << std::endl;命令模式(Command):// 命令接口class Command {public: virtual ~Command() = default; virtual void execute() = 0; virtual void undo() = 0;};// 接收者class Receiver {public: void action() { std::cout << "Receiver action" << std::endl; } void reverseAction() { std::cout << "Receiver reverse action" << std::endl; }};// 具体命令class ConcreteCommand : public Command {private: Receiver& receiver;public: ConcreteCommand(Receiver& r) : receiver(r) {} void execute() override { receiver.action(); } void undo() override { receiver.reverseAction(); }};// 调用者class Invoker {private: std::vector<std::unique_ptr<Command>> commands;public: void setCommand(std::unique_ptr<Command> command) { commands.push_back(std::move(command)); } void executeCommands() { for (auto& command : commands) { command->execute(); } } void undoCommands() { for (auto it = commands.rbegin(); it != commands.rend(); ++it) { (*it)->undo(); } }};// 使用Receiver receiver;Invoker invoker;invoker.setCommand(std::make_unique<ConcreteCommand>(receiver));invoker.setCommand(std::make_unique<ConcreteCommand>(receiver));invoker.executeCommands();invoker.undoCommands();状态模式(State):// 状态接口class State {public: virtual ~State() = default; virtual void handle() = 0;};// 上下文class Context {private: std::unique_ptr<State> state;public: void setState(std::unique_ptr<State> s) { state = std::move(s); } void request() { state->handle(); }};// 具体状态class ConcreteStateA : public State {private: Context& context;public: ConcreteStateA(Context& ctx) : context(ctx) {} void handle() override { std::cout << "State A handling" << std::endl; context.setState(std::make_unique<ConcreteStateB>(context)); }};class ConcreteStateB : public State {private: Context& context;public: ConcreteStateB(Context& ctx) : context(ctx) {} void handle() override { std::cout << "State B handling" << std::endl; context.setState(std::make_unique<ConcreteStateA>(context)); }};// 使用Context context;context.setState(std::make_unique<ConcreteStateA>(context));context.request(); // State Acontext.request(); // State Bcontext.request(); // State A模板方法模式(Template Method)// 抽象类class AbstractClass {public: virtual ~AbstractClass() = default; void templateMethod() { primitiveOperation1(); primitiveOperation2(); hook(); }protected: virtual void primitiveOperation1() = 0; virtual void primitiveOperation2() = 0; virtual void hook() {} // 钩子方法,可选实现};// 具体类class ConcreteClass : public AbstractClass {protected: void primitiveOperation1() override { std::cout << "Primitive operation 1" << std::endl; } void primitiveOperation2() override { std::cout << "Primitive operation 2" << std::endl; } void hook() override { std::cout << "Hook called" << std::endl; }};// 使用std::unique_ptr<AbstractClass> obj = std::make_unique<ConcreteClass>();obj->templateMethod();责任链模式(Chain of Responsibility)// 处理者接口class Handler {protected: std::unique_ptr<Handler> next;public: virtual ~Handler() = default; void setNext(std::unique_ptr<Handler> h) { next = std::move(h); } virtual void handleRequest(int request) { if (next) { next->handleRequest(request); } }};// 具体处理者class ConcreteHandlerA : public Handler {public: void handleRequest(int request) override { if (request >= 0 && request < 10) { std::cout << "Handler A handles request " << request << std::endl; } else { Handler::handleRequest(request); } }};class ConcreteHandlerB : public Handler {public: void handleRequest(int request) override { if (request >= 10 && request < 20) { std::cout << "Handler B handles request " << request << std::endl; } else { Handler::handleRequest(request); } }};// 使用auto handlerA = std::make_unique<ConcreteHandlerA>();auto handlerB = std::make_unique<ConcreteHandlerB>();handlerA->setNext(std::move(handlerB));handlerA->handleRequest(5); // Handler AhandlerA->handleRequest(15); // Handler B最佳实践1. 优先使用组合而非继承// 推荐:组合class Engine {public: void start() { std::cout << "Engine started" << std::endl; }};class Car {private: Engine engine;public: void start() { engine.start(); }};// 不推荐:过度继承class Vehicle {public: virtual void start() = 0;};class Car : public Vehicle {public: void start() override { std::cout << "Car started" << std::endl; }};2. 使用智能指针管理对象生命周期// 推荐std::unique_ptr<Factory> factory = std::make_unique<FactoryA>();auto product = factory->createProduct();// 不推荐Factory* factory = new FactoryA();auto product = factory->createProduct();delete factory;3. 遵循 SOLID 原则单一职责原则(SRP)开闭原则(OCP)里氏替换原则(LSP)接口隔离原则(ISP)依赖倒置原则(DIP)4. 使用 RAII 确保资源管理class ResourceManager {private: std::unique_ptr<Resource> resource;public: ResourceManager() : resource(std::make_unique<Resource>()) {} // 析构函数自动释放资源};5. 避免过度设计// 简单场景不需要复杂模式int add(int a, int b) { return a + b;}// 复杂场景才使用设计模式class Calculator {public: virtual int calculate(int a, int b) = 0;};
阅读 0·2月18日 17:36

C++11/14/17/20 新特性有哪些

C++11/14/17/20 新特性C++ 标准不断演进,每个新版本都引入了许多强大的特性,显著提升了开发效率和代码质量。C++11 新特性自动类型推导(auto):// 自动推导类型auto x = 42; // intauto y = 3.14; // doubleauto z = "Hello"; // const char*auto& ref = x; // int&auto&& universal = x; // int& (万能引用)// 与迭代器配合使用std::vector<int> vec = {1, 2, 3};for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << std::endl;}// 范围 for 循环for (auto& val : vec) { val *= 2;}范围 for 循环:std::vector<int> vec = {1, 2, 3, 4, 5};// 只读遍历for (const auto& val : vec) { std::cout << val << " ";}// 修改遍历for (auto& val : vec) { val *= 2;}// 初始化列表for (auto val : {1, 2, 3, 4, 5}) { std::cout << val << " ";}Lambda 表达式:// 基本语法auto lambda = [](int x, int y) { return x + y;};// 捕获变量int threshold = 10;auto filtered = [threshold](int x) { return x > threshold;};// 引用捕获int sum = 0;auto accumulate = [&sum](int x) { sum += x;};// 混合捕获int a = 1, b = 2;auto mixed = [a, &b]() { return a + b;};// 可变 lambdaauto variadic = [](auto... args) { return (args + ... + 0);};// 使用std::vector<int> vec = {5, 15, 25};auto it = std::find_if(vec.begin(), vec.end(), filtered);智能指针:#include <memory>// unique_ptr - 独占所有权auto ptr1 = std::make_unique<int>(42);auto ptr2 = std::move(ptr1); // 转移所有权// shared_ptr - 共享所有权auto shared1 = std::make_shared<int>(100);auto shared2 = shared1; // 引用计数增加std::cout << shared1.use_count() << std::endl; // 2// weak_ptr - 弱引用std::weak_ptr<int> weak = shared1;if (auto locked = weak.lock()) { std::cout << *locked << std::endl;}右值引用与移动语义:class MyString {private: char* data; size_t size;public: MyString(const char* str = ""); MyString(const MyString& other); // 拷贝构造 MyString(MyString&& other) noexcept; // 移动构造 MyString& operator=(const MyString& other); // 拷贝赋值 MyString& operator=(MyString&& other) noexcept; // 移动赋值};// 使用MyString str1 = "Hello";MyString str2 = std::move(str1); // 移动而非拷贝nullptr:// C++11 之前int* ptr1 = NULL;void func(int* ptr);void func(int value);func(NULL); // 歧义,可能调用 func(int)// C++11int* ptr2 = nullptr;func(nullptr); // 明确调用 func(int*)constexpr:// 编译期常量constexpr int factorial(int n) { return n <= 1 ? 1 : n * factorial(n - 1);}constexpr int result = factorial(5); // 编译期计算// 字面量类型struct Point { constexpr Point(double x, double y) : x(x), y(y) {} constexpr double distance() const { return x * x + y * y; } double x, y;};constexpr Point p(3.0, 4.0);constexpr double dist = p.distance(); // 25.0C++14 新特性泛型 lambda:// C++11auto add = [](int a, int b) { return a + b; };// C++14 - 泛型 lambdaauto genericAdd = [](auto a, auto b) { return a + b;};auto result1 = genericAdd(10, 20); // intauto result2 = genericAdd(3.14, 2.71); // double变量模板:template <typename T>constexpr T pi = T(3.1415926535897932385);// 使用double d = pi<double>;float f = pi<float>;二进制字面量:int binary = 0b1010; // 10int octal = 012; // 10int hex = 0xA; // 10函数返回类型推导:// C++11auto add(int a, int b) -> int { return a + b;}// C++14 - 自动推导返回类型auto add(int a, int b) { return a + b;}// 复杂返回类型auto getVector() { return std::vector<int>{1, 2, 3};}std::make_unique:// C++11auto ptr = std::unique_ptr<int>(new int(42));// C++14auto ptr = std::make_unique<int>(42);C++17 新特性结构化绑定:std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}};// C++17 之前for (auto it = myMap.begin(); it != myMap.end(); ++it) { int key = it->first; std::string value = it->second;}// C++17for (const auto& [key, value] : myMap) { std::cout << key << ": " << value << std::endl;}// 元组解包auto [x, y, z] = std::make_tuple(1, 2.0, "three");if constexpr:template <typename T>auto process(T value) { if constexpr (std::is_integral_v<T>) { return value * 2; } else if constexpr (std::is_floating_point_v<T>) { return value / 2; } else { return value; }}// 使用process(10); // 20process(3.14); // 1.57std::optional:#include <optional>std::optional<int> divide(int a, int b) { if (b == 0) { return std::nullopt; } return a / b;}// 使用auto result = divide(10, 2);if (result) { std::cout << *result << std::endl;} else { std::cout << "Division by zero" << std::endl;}// 提供默认值int value = result.value_or(0);std::variant:#include <variant>std::variant<int, double, std::string> value;value = 42;value = 3.14;value = "Hello";// 访问std::visit([](auto&& arg) { std::cout << arg << std::endl;}, value);// 检查类型if (std::holds_alternative<int>(value)) { int intValue = std::get<int>(value);}std::any:#include <any>std::any value = 42;value = 3.14;value = "Hello";// 访问if (value.type() == typeid(int)) { int intValue = std::any_cast<int>(value);}折叠表达式:// C++17template <typename... Args>auto sum(Args... args) { return (args + ... + 0);}// 使用auto total = sum(1, 2, 3, 4, 5); // 15// 左折叠template <typename... Args>bool allTrue(Args... args) { return (args && ...);}// 右折叠template <typename... Args>void printAll(Args... args) { (std::cout << ... << args) << std::endl;}std::string_view:#include <string_view>void printString(std::string_view str) { std::cout << str << std::endl;}// 使用std::string str = "Hello";const char* cstr = "World";printString(str); // OKprintString(cstr); // OKprintString("Test"); // OK,无需创建临时 string 对象C++20 新特性概念(Concepts):#include <concepts>// 定义概念template <typename T>concept Integral = std::is_integral_v<T>;template <typename T>concept Sortable = requires(T t) { { t.begin() } -> std::same_as<typename T::iterator>; { t.end() } -> std::same_as<typename T::iterator>;};// 使用概念约束模板template <Integral T>T add(T a, T b) { return a + b;}// requires 子句template <typename T>requires std::is_integral_v<T>T multiply(T a, T b) { return a * b;}// 简写语法void process(Integral auto value) { std::cout << value << std::endl;}三向比较(Spaceship Operator):struct Point { int x, y; // 自动生成比较运算符 auto operator<=>(const Point&) const = default;};// 使用Point p1{1, 2};Point p2{1, 3};if (p1 < p2) { std::cout << "p1 < p2" << std::endl;}if (p1 == p2) { std::cout << "p1 == p2" << std::endl;}范围库(Ranges):#include <ranges>#include <vector>#include <algorithm>std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};// 过滤偶数auto evens = numbers | std::views::filter([](int n) { return n % 2 == 0;});// 转换auto squared = numbers | std::views::transform([](int n) { return n * n;});// 组合操作auto result = numbers | std::views::filter([](int n) { return n % 2 == 0; }) | std::views::transform([](int n) { return n * n; });// 使用for (auto n : result) { std::cout << n << " ";}协程(Coroutines):#include <coroutine>// 简单的生成器template <typename T>struct Generator { struct promise_type { T current_value; Generator get_return_object() { return Generator{std::coroutine_handle<promise_type>::from_promise(*this)}; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } std::suspend_always yield_value(T value) { current_value = value; return {}; } void return_void() {} void unhandled_exception() { std::terminate(); } }; std::coroutine_handle<promise_type> handle; Generator(std::coroutine_handle<promise_type> h) : handle(h) {} ~Generator() { if (handle) handle.destroy(); } bool next() { handle.resume(); return !handle.done(); } T value() { return handle.promise().current_value; }};Generator<int> fibonacci() { int a = 0, b = 1; while (true) { co_yield a; int temp = a + b; a = b; b = temp; }}// 使用auto gen = fibonacci();for (int i = 0; i < 10; ++i) { gen.next(); std::cout << gen.value() << " ";}模块(Modules):// math.ixx (模块接口)export module math;export int add(int a, int b) { return a + b;}export double multiply(double a, double b) { return a * b;}// main.cppimport math;int main() { int result = add(10, 20); return 0;}std::format:#include <format>std::string name = "Alice";int age = 30;// 格式化字符串std::string message = std::format("Name: {}, Age: {}", name, age);// 带格式的数字double pi = 3.14159;std::string formatted = std::format("Pi: {:.2f}", pi); // Pi: 3.14// 填充和对齐std::string padded = std::format("{:>10}", "Hello"); // " Hello"最佳实践1. 优先使用 auto 进行类型推导// 推荐auto it = vec.begin();auto result = std::make_unique<int>(42);// 不推荐std::vector<int>::iterator it = vec.begin();std::unique_ptr<int> result(new int(42));2. 使用智能指针管理资源// 推荐auto ptr = std::make_unique<Resource>();// 不推荐Resource* ptr = new Resource();3. 使用 nullptr 代替 NULL// 推荐int* ptr = nullptr;// 不推荐int* ptr = NULL;4. 使用 constexpr 进行编译期计算// 推荐constexpr int size = 1024;// 不推荐const int size = 1024;5. 使用范围 for 循环// 推荐for (const auto& val : vec) { std::cout << val << std::endl;}// 不推荐for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << std::endl;}
阅读 0·2月18日 17:36

C++ 模板的特化与偏特化如何使用

C++ 模板的特化与偏特化模板是 C++ 泛型编程的核心机制,而模板特化和偏特化则为模板提供了更精细的控制能力,允许为特定类型提供定制化的实现。模板基础函数模板:template <typename T>T max(T a, T b) { return (a > b) ? a : b;}// 使用int result = max(10, 20); // T = intdouble result2 = max(3.14, 2.71); // T = double类模板:template <typename T>class Stack {private: std::vector<T> elements;public: void push(const T& element) { elements.push_back(element); } T pop() { T element = elements.back(); elements.pop_back(); return element; }};// 使用Stack<int> intStack;Stack<std::string> stringStack;模板特化全特化(Full Specialization):为所有模板参数提供具体类型,完全替换模板定义。// 通用模板template <typename T>class Vector {public: void push(const T& value) { std::cout << "Generic push: " << value << std::endl; }};// bool 类型的全特化template <>class Vector<bool> {public: void push(bool value) { std::cout << "Bool push: " << (value ? "true" : "false") << std::endl; }};// 使用Vector<int> intVec;intVec.push(42); // 输出: Generic push: 42Vector<bool> boolVec;boolVec.push(true); // 输出: Bool push: true函数模板特化:// 通用模板template <typename T>bool compare(T a, T b) { std::cout << "Generic compare" << std::endl; return a < b;}// const char* 的特化template <>bool compare<const char*>(const char* a, const char* b) { std::cout << "String compare" << std::endl; return strcmp(a, b) < 0;}// 使用compare(10, 20); // 输出: Generic comparecompare("hello", "world"); // 输出: String compare模板偏特化偏特化(Partial Specialization)只适用于类模板,允许部分指定模板参数。基本示例:// 通用模板:两个类型参数template <typename T, typename U>class Pair {public: T first; U second; void print() { std::cout << "Pair<" << typeid(T).name() << ", " << typeid(U).name() << ">" << std::endl; }};// 偏特化:两个类型参数相同template <typename T>class Pair<T, T> {public: T first; T second; void print() { std::cout << "Pair<" << typeid(T).name() << ", " << typeid(T).name() << "> (Same types)" << std::endl; }};// 偏特化:第二个参数是指针template <typename T>class Pair<T, T*> {public: T first; T* second; void print() { std::cout << "Pair<" << typeid(T).name() << ", " << typeid(T).name() << "*> (Pointer)" << std::endl; }};// 使用Pair<int, double> p1; // 使用通用模板p1.print(); // Pair<int, double>Pair<int, int> p2; // 使用偏特化(相同类型)p2.print(); // Pair<int, int> (Same types)Pair<int, int*> p3; // 使用偏特化(指针)p3.print(); // Pair<int, int*> (Pointer)指针和引用的偏特化// 通用模板template <typename T>class TypeInfo {public: static const char* name() { return "Unknown type"; }};// 指针类型的偏特化template <typename T>class TypeInfo<T*> {public: static const char* name() { return "Pointer type"; }};// 引用类型的偏特化template <typename T>class TypeInfo<T&> {public: static const char* name() { return "Reference type"; }};// const 类型的偏特化template <typename T>class TypeInfo<const T> {public: static const char* name() { return "Const type"; }};// 使用std::cout << TypeInfo<int>::name() << std::endl; // Unknown typestd::cout << TypeInfo<int*>::name() << std::endl; // Pointer typestd::cout << TypeInfo<int&>::name() << std::endl; // Reference typestd::cout << TypeInfo<const int>::name() << std::endl; // Const typeSFINAE(替换失败并非错误)SFINAE 是模板元编程的重要技术,允许在模板参数替换失败时排除该模板,而不是产生编译错误。基本示例:// 检查类型是否有 value_type 成员template <typename T>class has_value_type { template <typename U> static auto test(int) -> decltype(typename U::value_type(), std::true_type{}); template <typename> static std::false_type test(...);public: static constexpr bool value = decltype(test<T>(0))::value;};// 使用 SFINAE 的函数重载template <typename T>typename std::enable_if<has_value_type<T>::value, void>::typeprocess(T container) { std::cout << "Container has value_type" << std::endl;}template <typename T>typename std::enable_if<!has_value_type<T>::value, void>::typeprocess(T value) { std::cout << "Type doesn't have value_type" << std::endl;}// 使用std::vector<int> vec;process(vec); // Container has value_typeint x = 42;process(x); // Type doesn't have value_typeC++17 的 if constexpr:template <typename T>void printTypeInfo(T value) { if constexpr (std::is_pointer_v<T>) { std::cout << "Pointer type" << std::endl; } else if constexpr (std::is_integral_v<T>) { std::cout << "Integral type" << std::endl; } else if constexpr (std::is_floating_point_v<T>) { std::cout << "Floating point type" << std::endl; } else { std::cout << "Other type" << std::endl; }}// 使用int* ptr = nullptr;printTypeInfo(ptr); // Pointer typeint num = 42;printTypeInfo(num); // Integral typedouble d = 3.14;printTypeInfo(d); // Floating point type模板元编程编译期计算:// 编译期计算阶乘template <int N>struct Factorial { static constexpr int value = N * Factorial<N - 1>::value;};// 特化作为递归终止条件template <>struct Factorial<0> { static constexpr int value = 1;};// 使用constexpr int result = Factorial<5>::value; // 120编译期判断:template <typename T>struct IsPointer { static constexpr bool value = false;};template <typename T>struct IsPointer<T*> { static constexpr bool value = true;};// 使用static_assert(IsPointer<int*>::value == true);static_assert(IsPointer<int>::value == false);类型萃取(Type Traits)C++11 引入了 <type_traits> 头文件,提供了丰富的类型萃取工具。常用类型萃取:#include <type_traits>// 检查类型属性static_assert(std::is_integral_v<int> == true);static_assert(std::is_floating_point_v<double> == true);static_assert(std::is_pointer_v<int*> == true);static_assert(std::is_reference_v<int&> == true);static_assert(std::is_const_v<const int> == true);// 类型转换using IntPtr = std::add_pointer_t<int>; // int*using ConstInt = std::add_const_t<int>; // const intusing RemoveConst = std::remove_const_t<const int>; // int// 条件类型template <typename T>using ElementType = typename std::conditional< std::is_pointer_v<T>, std::remove_pointer_t<T>, T>::type;// 使用static_assert(std::is_same_v<ElementType<int*>, int>);static_assert(std::is_same_v<ElementType<int>, int>);实际应用示例智能指针的删除器特化:template <typename T>class SmartPtr {private: T* ptr;public: explicit SmartPtr(T* p = nullptr) : ptr(p) {} ~SmartPtr() { delete ptr; }};// 数组类型的特化template <typename T>class SmartPtr<T[]> {private: T* ptr;public: explicit SmartPtr(T* p = nullptr) : ptr(p) {} ~SmartPtr() { delete[] ptr; }};// 使用SmartPtr<int> ptr1(new int(42));SmartPtr<int[]> ptr2(new int[10]);容器的优化特化:template <typename T, size_t N>class FixedArray {private: T data[N];public: T& operator[](size_t index) { return data[index]; }};// bool 类型的特化,使用位压缩template <size_t N>class FixedArray<bool, N> {private: unsigned char data[(N + 7) / 8];public: bool operator[](size_t index) { return (data[index / 8] >> (index % 8)) & 1; }};最佳实践1. 优先使用类型萃取而非手动特化// 推荐template <typename T>void process(T value) { if constexpr (std::is_pointer_v<T>) { // 处理指针 } else { // 处理非指针 }}// 不推荐template <typename T>void process(T value);template <typename T>void process(T* value);2. 使用 constexpr 进行编译期计算// C++11/14template <int N>struct Factorial { static constexpr int value = N * Factorial<N - 1>::value;};// C++17constexpr int factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1);}3. 使用概念(C++20)约束模板template <typename T>concept Integral = std::is_integral_v<T>;template <Integral T>T add(T a, T b) { return a + b;}// 使用add(10, 20); // OKadd(3.14, 2.71); // 编译错误4. 避免过度复杂的模板元编程// 不推荐:过度复杂template <typename T>struct ComplexMetaProgramming { // 大量嵌套模板};// 推荐:简洁明了template <typename T>void simpleFunction(T value) { // 简单直接的实现}注意事项函数模板不支持偏特化,只能全特化特化版本必须在主模板之后声明特化版本必须与主模板的接口一致SFINAE 可能导致编译错误信息难以理解过度使用模板特化可能导致代码膨胀C++20 的概念可以替代部分 SFINAE 用法,提供更好的可读性
阅读 0·2月18日 17:35

C++ 异常处理机制如何使用

C++ 异常处理机制C++ 异常处理提供了一种结构化的错误处理方式,允许程序在运行时检测和处理错误,而不会导致程序崩溃。异常处理基础基本语法:#include <iostream>#include <stdexcept>int divide(int a, int b) { if (b == 0) { throw std::runtime_error("Division by zero"); } return a / b;}int main() { try { int result = divide(10, 0); std::cout << "Result: " << result << std::endl; } catch (const std::runtime_error& e) { std::cerr << "Error: " << e.what() << std::endl; } catch (...) { std::cerr << "Unknown error occurred" << std::endl; } return 0;}标准异常类异常类层次结构:std::exception├── std::logic_error│ ├── std::invalid_argument│ ├── std::domain_error│ ├── std::length_error│ └── std::out_of_range└── std::runtime_error ├── std::range_error ├── std::overflow_error └── std::underflow_error使用标准异常:#include <stdexcept>void processValue(int value) { if (value < 0) { throw std::invalid_argument("Value must be non-negative"); } if (value > 100) { throw std::out_of_range("Value must be <= 100"); } // 处理逻辑}void allocateMemory(size_t size) { try { int* ptr = new int[size]; // 使用内存 delete[] ptr; } catch (const std::bad_alloc& e) { std::cerr << "Memory allocation failed: " << e.what() << std::endl; throw; }}自定义异常类基本自定义异常:class MyException : public std::exception {private: std::string message;public: MyException(const std::string& msg) : message(msg) {} const char* what() const noexcept override { return message.c_str(); }};// 使用void riskyOperation() { throw MyException("Something went wrong");}带错误代码的异常:class DatabaseException : public std::runtime_error {private: int errorCode;public: DatabaseException(const std::string& msg, int code) : std::runtime_error(msg), errorCode(code) {} int getErrorCode() const noexcept { return errorCode; }};// 使用void queryDatabase() { throw DatabaseException("Connection failed", 1001);}try { queryDatabase();} catch (const DatabaseException& e) { std::cerr << "Database error " << e.getErrorCode() << ": " << e.what() << std::endl;}异常规范noexcept 规范:// C++11 之前的异常规范(已弃用)void oldFunction() throw(std::runtime_error) { // 可能抛出 runtime_error}// C++11 的 noexceptvoid safeFunction() noexcept { // 保证不抛出异常}// 条件 noexcepttemplate <typename T>void conditionalNoexcept(T&& value) noexcept(std::is_nothrow_move_constructible_v<T>) { // 根据 T 的移动构造函数是否 noexcept 来决定}noexcept 的作用:优化编译器生成的代码允许标准库选择更高效的实现(如 vector 移动)提供更好的错误处理保证RAII 与异常安全异常安全级别:1. 基本保证(Basic Guarantee):class ResourceManager {private: int* resource1; int* resource2;public: ResourceManager() : resource1(nullptr), resource2(nullptr) { resource1 = new int; resource2 = new int; } ~ResourceManager() { delete resource1; delete resource2; } void modify() { // 即使抛出异常,对象仍处于有效状态 int* temp = new int; delete resource1; resource1 = temp; // 如果后续操作抛出异常,资源1已更新,对象仍然有效 }};2. 强烈保证(Strong Guarantee):class StrongGuaranteeExample {private: std::vector<int> data;public: void update(const std::vector<int>& newData) { // 创建副本 std::vector<int> temp = data; // 修改副本 temp.insert(temp.end(), newData.begin(), newData.end()); // 原子交换 std::swap(data, temp); // 如果抛出异常,原数据不受影响 }};3. 不抛出保证(No-throw Guarantee):class NoThrowExample {private: std::unique_ptr<int> ptr;public: void reset() noexcept { ptr.reset(); // unique_ptr::reset 是 noexcept }};智能指针与异常安全使用智能指针确保异常安全:// 不推荐:手动管理内存void unsafeFunction() { int* ptr = new int(42); // 如果这里抛出异常,ptr 会泄漏 someRiskyOperation(); delete ptr;}// 推荐:使用智能指针void safeFunction() { auto ptr = std::make_unique<int>(42); // 即使抛出异常,ptr 也会自动释放 someRiskyOperation();}std::lock_guard 与异常安全:std::mutex mtx;void threadSafeOperation() { std::lock_guard<std::mutex> lock(mtx); // 临界区代码 // 即使抛出异常,锁也会自动释放 riskyOperation();}异常捕获与重新抛出捕获并重新抛出:void process() { try { riskyOperation(); } catch (const std::exception& e) { // 记录日志 logError(e.what()); // 重新抛出 throw; }}// 使用 std::current_exception 保存异常std::exception_ptr currentException;void saveException() { try { riskyOperation(); } catch (...) { currentException = std::current_exception(); }}void rethrowException() { if (currentException) { std::rethrow_exception(currentException); }}异常与构造函数/析构函数构造函数中的异常:class MyClass {private: int* data; std::string name;public: MyClass(const std::string& n, size_t size) : name(n) { data = new int[size]; // 如果后续操作失败,构造函数抛出异常 if (size == 0) { delete[] data; // 清理已分配的资源 throw std::invalid_argument("Size cannot be zero"); } } ~MyClass() { delete[] data; }};析构函数中的异常:class MyClass {private: std::unique_ptr<int> ptr;public: ~MyClass() noexcept { // 析构函数不应该抛出异常 try { cleanup(); } catch (...) { // 吞掉异常或记录日志 std::cerr << "Exception in destructor" << std::endl; } } void cleanup() { // 清理逻辑 }};异常与函数指针异常规范与函数指针:// noexcept 函数指针using NoThrowFunction = void(*)() noexcept;void safeFunction() noexcept { // 不抛出异常}void unsafeFunction() { // 可能抛出异常}NoThrowFunction func1 = safeFunction; // OK// NoThrowFunction func2 = unsafeFunction; // 编译错误最佳实践1. 按值抛出,按引用捕获// 推荐throw MyException("Error message");try { riskyOperation();} catch (const MyException& e) { // 按引用捕获 std::cerr << e.what() << std::endl;}// 不推荐throw new MyException("Error message"); // 不要抛出指针2. 捕获最具体的异常try { riskyOperation();} catch (const std::invalid_argument& e) { // 处理特定异常} catch (const std::runtime_error& e) { // 处理运行时错误} catch (const std::exception& e) { // 处理其他标准异常} catch (...) { // 处理未知异常}3. 使用 RAII 确保资源释放class FileHandler {private: FILE* file;public: FileHandler(const char* filename) { file = fopen(filename, "r"); if (!file) { throw std::runtime_error("Failed to open file"); } } ~FileHandler() noexcept { if (file) { fclose(file); } } // 禁止拷贝 FileHandler(const FileHandler&) = delete; FileHandler& operator=(const FileHandler&) = delete;};4. 异常只用于异常情况// 推荐:异常用于真正的错误void processValue(int value) { if (value < 0) { throw std::invalid_argument("Value must be non-negative"); } // 正常处理}// 不推荐:异常用于控制流void findElement(const std::vector<int>& vec, int target) { for (int val : vec) { if (val == target) { throw FoundException(); // 不要这样做 } }}5. 提供有意义的错误信息class DatabaseException : public std::runtime_error {public: DatabaseException(const std::string& operation, const std::string& reason) : std::runtime_error("Database error in " + operation + ": " + reason) {}};// 使用throw DatabaseException("query", "connection timeout");注意事项不要在析构函数中抛出异常构造函数中抛出异常时,确保已构造的成员被正确析构异常处理会增加运行时开销,避免在性能关键路径过度使用noexcept 函数如果抛出异常会调用 std::terminate跨 DLL 边界抛出异常可能导致问题异常对象应该轻量级,避免在异常中包含大量数据考虑使用错误码或 std::optional 作为异常的替代方案在多线程环境中,异常只在当前线程中传播
阅读 0·2月18日 17:34

C++ 并发编程与多线程如何实现

C++ 并发编程与多线程C++11 引入了标准化的多线程支持,提供了丰富的并发编程工具,包括线程、互斥锁、条件变量、原子操作等。线程基础创建线程:#include <thread>#include <iostream>void hello() { std::cout << "Hello from thread!" << std::endl;}int main() { // 创建线程 std::thread t(hello); // 等待线程完成 t.join(); return 0;}带参数的线程:void printMessage(const std::string& message, int count) { for (int i = 0; i < count; ++i) { std::cout << message << std::endl; }}int main() { std::string msg = "Hello"; std::thread t(printMessage, msg, 3); t.join(); return 0;}使用 lambda 表达式:int main() { int value = 42; std::thread t([value]() { std::cout << "Value: " << value << std::endl; }); t.join(); return 0;}互斥锁(Mutex)基本使用:#include <mutex>#include <thread>#include <iostream>std::mutex mtx;int counter = 0;void increment() { for (int i = 0; i < 10000; ++i) { std::lock_guard<std::mutex> lock(mtx); ++counter; }}int main() { std::thread t1(increment); std::thread t2(increment); t1.join(); t2.join(); std::cout << "Counter: " << counter << std::endl; // 20000 return 0;}unique_lock:std::mutex mtx;void process() { std::unique_lock<std::mutex> lock(mtx); // 可以手动解锁 lock.unlock(); // 执行一些不需要锁的操作 // 重新加锁 lock.lock();}// 条件变量配合使用std::mutex mtx;std::condition_variable cv;bool ready = false;void worker() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return ready; }); // 执行工作}try_lock:std::mutex mtx1, mtx2;void process() { std::unique_lock<std::mutex> lock1(mtx1, std::defer_lock); std::unique_lock<std::mutex> lock2(mtx2, std::defer_lock); if (std::try_lock(lock1, lock2) == -1) { // 成功获取两个锁 // 执行操作 } else { // 未能获取所有锁 }}条件变量(Condition Variable)基本使用:#include <condition_variable>#include <mutex>#include <thread>#include <queue>#include <iostream>std::mutex mtx;std::condition_variable cv;std::queue<int> dataQueue;bool finished = false;void producer() { for (int i = 0; i < 10; ++i) { { std::lock_guard<std::mutex> lock(mtx); dataQueue.push(i); std::cout << "Produced: " << i << std::endl; } cv.notify_one(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } { std::lock_guard<std::mutex> lock(mtx); finished = true; } cv.notify_all();}void consumer() { while (true) { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return !dataQueue.empty() || finished; }); if (dataQueue.empty() && finished) { break; } int value = dataQueue.front(); dataQueue.pop(); lock.unlock(); std::cout << "Consumed: " << value << std::endl; }}int main() { std::thread p(producer); std::thread c(consumer); p.join(); c.join(); return 0;}原子操作(Atomic)基本类型:#include <atomic>#include <thread>#include <iostream>std::atomic<int> atomicCounter(0);void increment() { for (int i = 0; i < 10000; ++i) { atomicCounter.fetch_add(1, std::memory_order_relaxed); }}int main() { std::thread t1(increment); std::thread t2(increment); t1.join(); t2.join(); std::cout << "Atomic counter: " << atomicCounter << std::endl; return 0;}内存顺序:std::atomic<bool> flag(false);std::atomic<int> data(0);void writer() { data.store(42, std::memory_order_release); flag.store(true, std::memory_order_release);}void reader() { while (!flag.load(std::memory_order_acquire)) { // 等待 } int value = data.load(std::memory_order_acquire); std::cout << "Data: " << value << std::endl;}CAS(Compare-And-Swap):std::atomic<int> value(0);bool updateIfEqual(int expected, int desired) { return value.compare_exchange_weak(expected, desired);}// 使用if (updateIfEqual(0, 1)) { std::cout << "Updated successfully" << std::endl;} else { std::cout << "Update failed" << std::endl;}线程局部存储thread_local:#include <thread>#include <iostream>thread_local int threadLocalVar = 0;void printThreadId() { ++threadLocalVar; std::cout << "Thread ID: " << std::this_thread::get_id() << ", Value: " << threadLocalVar << std::endl;}int main() { std::thread t1(printThreadId); std::thread t2(printThreadId); std::thread t3(printThreadId); t1.join(); t2.join(); t3.join(); return 0;}异步操作(Future 和 Promise)基本使用:#include <future>#include <iostream>int calculate() { std::this_thread::sleep_for(std::chrono::seconds(2)); return 42;}int main() { std::future<int> result = std::async(std::launch::async, calculate); std::cout << "Doing other work..." << std::endl; int value = result.get(); // 等待结果 std::cout << "Result: " << value << std::endl; return 0;}Promise:#include <future>#include <thread>#include <iostream>void setValue(std::promise<int> prom) { std::this_thread::sleep_for(std::chrono::seconds(1)); prom.set_value(100);}int main() { std::promise<int> prom; std::future<int> fut = prom.get_future(); std::thread t(setValue, std::move(prom)); int value = fut.get(); std::cout << "Value: " << value << std::endl; t.join(); return 0;}Packaged Task:#include <future>#include <functional>int add(int a, int b) { return a + b;}int main() { std::packaged_task<int(int, int)> task(add); std::future<int> result = task.get_future(); std::thread t(std::move(task), 10, 20); t.join(); std::cout << "Result: " << result.get() << std::endl; return 0;}线程池实现简单线程池:#include <thread>#include <mutex>#include <condition_variable>#include <queue>#include <functional>#include <vector>class ThreadPool {private: std::vector<std::thread> workers; std::queue<std::function<void()>> tasks; std::mutex queueMutex; std::condition_variable condition; bool stop;public: ThreadPool(size_t threads) : stop(false) { for (size_t i = 0; i < threads; ++i) { workers.emplace_back([this] { while (true) { std::function<void()> task; { std::unique_lock<std::mutex> lock(this->queueMutex); this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); }); if (this->stop && this->tasks.empty()) { return; } task = std::move(this->tasks.front()); this->tasks.pop(); } task(); } }); } } template <class F, class... Args> auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type> { using return_type = typename std::result_of<F(Args...)>::type; auto task = std::make_shared<std::packaged_task<return_type()>>( std::bind(std::forward<F>(f), std::forward<Args>(args)...) ); std::future<return_type> res = task->get_future(); { std::unique_lock<std::mutex> lock(queueMutex); if (stop) { throw std::runtime_error("enqueue on stopped ThreadPool"); } tasks.emplace([task]() { (*task)(); }); } condition.notify_one(); return res; } ~ThreadPool() { { std::unique_lock<std::mutex> lock(queueMutex); stop = true; } condition.notify_all(); for (std::thread& worker : workers) { worker.join(); } }};// 使用int main() { ThreadPool pool(4); auto result1 = pool.enqueue([](int a, int b) { return a + b; }, 10, 20); auto result2 = pool.enqueue([](int a, int b) { return a * b; }, 5, 6); std::cout << "Result 1: " << result1.get() << std::endl; std::cout << "Result 2: " << result2.get() << std::endl; return 0;}最佳实践1. 避免数据竞争// 错误:数据竞争int sharedData = 0;std::thread t1([&](){ ++sharedData; });std::thread t2([&](){ ++sharedData; });// 正确:使用互斥锁std::mutex mtx;int sharedData = 0;std::thread t1([&](){ std::lock_guard<std::mutex> lock(mtx); ++sharedData; });std::thread t2([&](){ std::lock_guard<std::mutex> lock(mtx); ++sharedData; });2. 避免死锁// 错误:可能导致死锁std::mutex mtx1, mtx2;void thread1() { std::lock_guard<std::mutex> lock1(mtx1); std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::lock_guard<std::mutex> lock2(mtx2);}void thread2() { std::lock_guard<std::mutex> lock2(mtx2); std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::lock_guard<std::mutex> lock1(mtx1);}// 正确:使用 std::lockvoid thread1Safe() { std::lock(mtx1, mtx2); std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock); std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);}void thread2Safe() { std::lock(mtx1, mtx2); std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock); std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);}3. 使用 RAII 管理锁// 推荐void safeFunction() { std::lock_guard<std::mutex> lock(mtx); // 临界区代码} // 自动释放锁// 不推荐void unsafeFunction() { mtx.lock(); // 临界区代码 mtx.unlock(); // 可能忘记或异常导致未释放}4. 优先使用原子操作// 推荐:原子操作std::atomic<int> counter(0);++counter;// 不推荐:互斥锁(对于简单操作)std::mutex mtx;int counter = 0;{ std::lock_guard<std::mutex> lock(mtx); ++counter;}注意事项始终确保线程被正确 join 或 detach避免在析构函数中使用互斥锁注意条件变量的虚假唤醒合理选择内存顺序,避免过度使用 memoryorderseq_cst避免过度细粒度的锁,可能导致性能下降使用线程池管理大量短期任务注意异常安全,确保资源正确释放避免在多线程环境中使用全局变量
阅读 0·2月18日 17:34

C++ 内存管理与内存泄漏如何避免

C++ 内存管理与内存泄漏C++ 提供了强大的内存管理能力,但也要求开发者对内存生命周期有清晰的认识。不当的内存管理会导致内存泄漏、悬空指针、重复释放等严重问题。C++ 内存区域1. 栈(Stack)存储局部变量、函数参数、返回地址自动分配和释放大小有限(通常几 MB)分配速度快2. 堆(Heap)动态分配的内存手动管理(new/delete)或智能指针管理大小受限于系统可用内存分配速度较慢3. 全局/静态区存储全局变量、静态变量程序启动时分配,结束时释放生命周期贯穿整个程序4. 常量区存储字符串常量、const 变量只读,不可修改5. 代码区存储程序二进制代码只读内存泄漏的原因1. 忘记释放内存void leakExample() { int* ptr = new int(42); // 忘记 delete ptr;}2. 异常导致跳过释放void leakWithException() { int* ptr = new int(42); someFunctionThatThrows(); // 如果抛出异常,ptr 不会被释放 delete ptr;}3. 循环引用class A {public: std::shared_ptr<B> b;};class B {public: std::shared_ptr<A> a; // 循环引用导致内存泄漏};auto a = std::make_shared<A>();auto b = std::make_shared<B>();a->b = b;b->a = a;4. 不当的指针赋值void lostPointer() { int* ptr = new int(42); ptr = new int(100); // 第一个分配的内存泄漏 delete ptr;}检测内存泄漏1. Valgrind(Linux)valgrind --leak-check=full --show-leak-kinds=all ./your_program2. AddressSanitizer(ASan)g++ -fsanitize=address -g your_program.cpp -o your_program./your_program3. Visual Studio 调试器使用 CRT 调试堆在代码开头添加:#define _CRTDBG_MAP_ALLOC#include <crtdbg.h>_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);4. 自定义内存跟踪class MemoryTracker {private: static std::unordered_map<void*, size_t> allocations;public: static void* allocate(size_t size) { void* ptr = malloc(size); allocations[ptr] = size; return ptr; } static void deallocate(void* ptr) { if (allocations.erase(ptr) == 0) { std::cerr << "Double free or invalid pointer: " << ptr << std::endl; } free(ptr); } static void reportLeaks() { if (!allocations.empty()) { std::cerr << "Memory leaks detected:" << std::endl; for (const auto& [ptr, size] : allocations) { std::cerr << " Leaked " << size << " bytes at " << ptr << std::endl; } } }};防止内存泄漏的方法1. 使用智能指针// 不推荐void badExample() { Resource* res = new Resource(); // 容易忘记 delete}// 推荐void goodExample() { auto res = std::make_unique<Resource>(); // 自动释放}2. 遵循 RAII 原则class FileHandler {private: FILE* file;public: FileHandler(const char* filename) { file = fopen(filename, "r"); if (!file) { throw std::runtime_error("Failed to open file"); } } ~FileHandler() { if (file) { fclose(file); } } // 禁止拷贝 FileHandler(const FileHandler&) = delete; FileHandler& operator=(const FileHandler&) = delete;};3. 使用标准容器// 不推荐void badContainer() { int* arr = new int[100]; // 处理数组 delete[] arr;}// 推荐void goodContainer() { std::vector<int> arr(100); // 自动管理内存}4. 正确处理异常// 不推荐void badException() { int* ptr = new int(42); riskyOperation(); // 可能抛出异常 delete ptr;}// 推荐void goodException() { auto ptr = std::make_unique<int>(42); riskyOperation(); // 即使抛出异常,ptr 也会被正确释放}内存对齐为什么需要内存对齐:CPU 访问对齐的内存更快某些架构要求特定类型必须对齐避免性能下降或程序崩溃对齐方式:// 使用 alignas 指定对齐struct alignas(16) AlignedStruct { int a; double b;};// 使用 alignof 查询对齐要求std::cout << "Alignment: " << alignof(AlignedStruct) << std::endl;// 使用 aligned_alloc 分配对齐内存void* ptr = aligned_alloc(16, 1024);内存池内存池的优点:减少内存碎片提高分配/释放速度减少系统调用次数简单实现:template <typename T, size_t BlockSize = 1024>class MemoryPool {private: struct Block { T data; Block* next; }; Block* freeList; std::vector<std::unique_ptr<Block[]>> blocks;public: MemoryPool() : freeList(nullptr) { allocateBlock(); } ~MemoryPool() = default; T* allocate() { if (!freeList) { allocateBlock(); } Block* block = freeList; freeList = freeList->next; return &block->data; } void deallocate(T* ptr) { Block* block = reinterpret_cast<Block*>(ptr); block->next = freeList; freeList = block; }private: void allocateBlock() { auto newBlock = std::make_unique<Block[]>(BlockSize); for (size_t i = 0; i < BlockSize - 1; ++i) { newBlock[i].next = &newBlock[i + 1]; } newBlock[BlockSize - 1].next = nullptr; freeList = &newBlock[0]; blocks.push_back(std::move(newBlock)); }};最佳实践1. 优先使用栈内存// 优先void stackPreferred() { int value = 42; process(value);}// 仅在必要时使用堆void heapWhenNeeded() { auto value = std::make_unique<int>(42); process(*value);}2. 使用标准库容器std::vector<int> vec; // 自动管理内存std::string str; // 自动管理内存std::map<int, int> map; // 自动管理内存3. 避免裸指针// 不推荐int* ptr = new int(42);// ... 使用 ptrdelete ptr;// 推荐auto ptr = std::make_unique<int>(42);// ... 使用 ptr// 自动释放4. 使用 const 正确性void process(const std::vector<int>& data); // 避免拷贝void modify(std::vector<int>& data); // 明确表示会修改5. 定期进行内存分析# 使用 Valgrind 检测内存泄漏valgrind --leak-check=full --show-leak-kinds=all ./your_program# 使用 AddressSanitizerg++ -fsanitize=address -g your_program.cpp -o your_program./your_program常见错误1. 重复释放int* ptr = new int(42);delete ptr;delete ptr; // 未定义行为2. 释放未分配的内存int* ptr;delete ptr; // 未定义行为3. 数组 new/delete 不匹配int* arr = new int[10];delete arr; // 错误,应该使用 delete[] arr4. 栈内存使用 deleteint value = 42;int* ptr = &value;delete ptr; // 错误,不能释放栈内存5. 悬空指针int* ptr = new int(42);delete ptr;*ptr = 100; // 未定义行为,悬空指针
阅读 0·2月18日 17:34

C++ STL 容器与算法如何使用

C++ STL 容器与算法C++ 标准模板库(STL)提供了丰富的容器和算法,是 C++ 编程的重要组成部分。熟练掌握 STL 可以显著提高开发效率和代码质量。序列容器std::vector动态数组,连续内存存储支持随机访问,O(1) 时间复杂度尾部插入和删除效率高 O(1),中间插入删除 O(n)自动扩容,通常容量翻倍#include <vector>#include <iostream>int main() { // 创建 vector std::vector<int> vec = {1, 2, 3, 4, 5}; // 访问元素 std::cout << vec[0] << std::endl; // 1 std::cout << vec.at(1) << std::endl; // 2(带边界检查) // 添加元素 vec.push_back(6); // 尾部添加 vec.emplace_back(7); // 原地构造 // 插入元素 vec.insert(vec.begin() + 2, 100); // 在位置 2 插入 // 删除元素 vec.pop_back(); // 删除最后一个 vec.erase(vec.begin()); // 删除第一个 // 容量信息 std::cout << "Size: " << vec.size() << std::endl; std::cout << "Capacity: " << vec.capacity() << std::endl; // 预留空间 vec.reserve(100); // 预留至少 100 个元素的空间 // 调整大小 vec.resize(50, 0); // 调整为 50 个元素,新元素初始化为 0 return 0;}std::deque双端队列,分段连续内存支持两端快速插入删除 O(1)支持随机访问 O(1)内存开销比 vector 大#include <deque>int main() { std::deque<int> dq = {1, 2, 3}; // 两端操作 dq.push_front(0); // 头部添加 dq.push_back(4); // 尾部添加 dq.pop_front(); // 头部删除 dq.pop_back(); // 尾部删除 // 随机访问 std::cout << dq[1] << std::endl; return 0;}std::list双向链表,非连续内存任意位置插入删除 O(1)不支持随机访问额外内存开销(每个节点两个指针)#include <list>int main() { std::list<int> lst = {1, 2, 3, 4, 5}; // 插入元素 auto it = lst.begin(); std::advance(it, 2); lst.insert(it, 100); // 在位置 2 插入 // 删除元素 lst.erase(lst.begin()); // 删除第一个 // 链表特有操作 lst.splice(lst.end(), lst, lst.begin()); // 移动元素 lst.sort(); // 排序 lst.unique(); // 去重 lst.reverse(); // 反转 return 0;}关联容器std::map键值对容器,按键排序基于红黑树实现查找、插入、删除 O(log n)键唯一#include <map>#include <string>int main() { std::map<std::string, int> scores; // 插入元素 scores["Alice"] = 90; scores["Bob"] = 85; scores.insert({"Charlie", 95}); // 访问元素 std::cout << scores["Alice"] << std::endl; // 90 // 查找元素 auto it = scores.find("Bob"); if (it != scores.end()) { std::cout << "Bob's score: " << it->second << std::endl; } // 删除元素 scores.erase("Alice"); // 遍历 for (const auto& [name, score] : scores) { std::cout << name << ": " << score << std::endl; } return 0;}std::unordered_map键值对容器,无序基于哈希表实现平均查找、插入、删除 O(1)最坏情况 O(n)#include <unordered_map>int main() { std::unordered_map<std::string, int> cache; cache["key1"] = 100; cache["key2"] = 200; // 快速查找 auto it = cache.find("key1"); if (it != cache.end()) { std::cout << it->second << std::endl; } return 0;}std::set有序集合,元素唯一基于红黑树实现查找、插入、删除 O(log n)#include <set>int main() { std::set<int> s = {5, 3, 1, 4, 2}; // 插入元素 s.insert(6); // 查找元素 auto it = s.find(3); if (it != s.end()) { std::cout << "Found: " << *it << std::endl; } // 删除元素 s.erase(1); // 遍历(自动排序) for (int val : s) { std::cout << val << " "; } return 0;}容器适配器std::stack后进先出(LIFO)基于 deque 或 vector 实现#include <stack>int main() { std::stack<int> stk; stk.push(1); stk.push(2); stk.push(3); while (!stk.empty()) { std::cout << stk.top() << " "; stk.pop(); } return 0;}std::queue先进先出(FIFO)基于 deque 实现#include <queue>int main() { std::queue<int> q; q.push(1); q.push(2); q.push(3); while (!q.empty()) { std::cout << q.front() << " "; q.pop(); } return 0;}std::priority_queue优先级队列默认大顶堆#include <queue>int main() { std::priority_queue<int> pq; // 大顶堆 pq.push(3); pq.push(1); pq.push(4); pq.push(2); while (!pq.empty()) { std::cout << pq.top() << " "; pq.pop(); } // 小顶堆 std::priority_queue<int, std::vector<int>, std::greater<int>> minPq; return 0;}STL 算法排序算法:#include <algorithm>#include <vector>int main() { std::vector<int> vec = {5, 2, 8, 1, 9, 3}; // 排序 std::sort(vec.begin(), vec.end()); // 部分排序 std::partial_sort(vec.begin(), vec.begin() + 3, vec.end()); // 第 n 大元素 std::nth_element(vec.begin(), vec.begin() + 2, vec.end()); return 0;}查找算法:int main() { std::vector<int> vec = {1, 2, 3, 4, 5}; // 二分查找(需要有序) auto it = std::lower_bound(vec.begin(), vec.end(), 3); // 查找 auto found = std::find(vec.begin(), vec.end(), 3); // 计数 int count = std::count(vec.begin(), vec.end(), 3); return 0;}变换算法:int main() { std::vector<int> vec1 = {1, 2, 3}; std::vector<int> vec2(3); // 复制 std::copy(vec1.begin(), vec1.end(), vec2.begin()); // 变换 std::transform(vec1.begin(), vec1.end(), vec2.begin(), [](int x) { return x * 2; }); // 填充 std::fill(vec2.begin(), vec2.end(), 0); // 生成 std::generate(vec2.begin(), vec2.end(), []() { return rand() % 100; }); return 0;}数值算法:#include <numeric>int main() { std::vector<int> vec = {1, 2, 3, 4, 5}; // 求和 int sum = std::accumulate(vec.begin(), vec.end(), 0); // 内积 std::vector<int> vec2 = {2, 3, 4, 5, 6}; int product = std::inner_product(vec.begin(), vec.end(), vec2.begin(), 0); // 差分 std::vector<int> diff(vec.size()); std::adjacent_difference(vec.begin(), vec.end(), diff.begin()); return 0;}迭代器迭代器分类:输入迭代器:只读,单向输出迭代器:只写,单向前向迭代器:读写,单向双向迭代器:读写,双向随机访问迭代器:读写,随机访问int main() { std::vector<int> vec = {1, 2, 3, 4, 5}; // 正向迭代器 for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; } // 反向迭代器 for (auto it = vec.rbegin(); it != vec.rend(); ++it) { std::cout << *it << " "; } // 常量迭代器 for (auto it = vec.cbegin(); it != vec.cend(); ++it) { std::cout << *it << " "; } return 0;}函数对象与 LambdaLambda 表达式:int main() { std::vector<int> vec = {5, 2, 8, 1, 9}; // 简单 lambda std::sort(vec.begin(), vec.end(), [](int a, int b) { return a < b; }); // 捕获变量 int threshold = 5; auto it = std::find_if(vec.begin(), vec.end(), [threshold](int x) { return x > threshold; }); // 可变 lambda int sum = 0; std::for_each(vec.begin(), vec.end(), [&sum](int x) mutable { sum += x; }); return 0;}std::function:#include <functional>int main() { std::function<int(int, int)> add = [](int a, int b) { return a + b; }; std::cout << add(10, 20) << std::endl; return 0;}最佳实践1. 选择合适的容器// 需要随机访问,频繁尾部插入std::vector<int> vec;// 需要频繁两端插入std::deque<int> dq;// 需要频繁中间插入删除std::list<int> lst;// 需要按键查找std::map<std::string, int> mp;// 需要快速查找,不关心顺序std::unordered_map<std::string, int> ump;2. 预分配空间std::vector<int> vec;vec.reserve(1000); // 预先分配空间,避免多次重新分配3. 使用 emplace 代替 pushstd::vector<std::pair<int, int>> vec;// 推荐vec.emplace_back(1, 2); // 原地构造// 不推荐vec.push_back(std::make_pair(1, 2)); // 可能产生临时对象4. 使用移动语义std::vector<std::string> vec;std::string str = "Hello";vec.push_back(std::move(str)); // 移动而非拷贝5. 使用算法代替循环std::vector<int> vec = {1, 2, 3, 4, 5};// 推荐int sum = std::accumulate(vec.begin(), vec.end(), 0);// 不推荐int sum = 0;for (int val : vec) { sum += val;}性能考虑时间复杂度:vector::push_back: 平均 O(1),最坏 O(n)list::insert: O(1)map::find: O(log n)unordered_map::find: 平均 O(1),最坏 O(n)空间复杂度:vector: 连续内存,无额外开销list: 每个节点额外两个指针map: 每个节点额外三个指针(红黑树)unordered_map: 每个节点额外一个指针 + 哈希表开销缓存友好性:vector: 最好(连续内存)deque: 中等(分段连续)list: 最差(分散内存)
阅读 0·2月18日 17:34