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

C++

C++ 是一种通用的、静态类型的编程语言,它具有高效性、灵活性和可移植性等特点。C++ 基于 C 语言,同时支持面向对象编程和泛型编程,可以用于开发各种类型的应用程序,如系统软件、游戏、桌面应用程序、移动应用程序等。 C++ 的主要特点包括: 高效性:C++ 是一种编译型语言,可以生成高效的本地代码,在性能要求高的应用程序中得到广泛应用; 面向对象编程:C++ 支持面向对象编程,包括封装、继承、多态等特性,使得开发人员可以更加灵活和高效地构建复杂的软件系统; 泛型编程:C++ 支持泛型编程,包括模板和泛型算法等特性,使得开发人员可以编写可重用的代码和算法; 可移植性:C++ 可以在多种平台和操作系统上运行,具有很高的可移植性; 标准化:C++ 有一个国际标准,称为 C++ 标准,规范了语言的语法、语义和库函数等方面,使得 C++ 的代码更加规范和可靠。 C++ 作为一种通用的编程语言,可以用于多种应用场景。在系统软件开发中,C++ 可以用于操作系统内核、驱动程序、网络协议栈等方面;在游戏开发中,C++ 可以用于游戏引擎、物理引擎、图形渲染等方面;在桌面应用程序和移动应用程序开发中,C++ 可以用于开发各种类型的应用程序,如音频和视频编辑、图像处理、数据库管理等方面。 如果您想要成为一名优秀的程序员,C++ 是一个非常有用的编程语言,它具有广泛的应用场景和丰富的编程资源,可以帮助您更加高效和灵活地解决实际问题。
C++
查看更多相关内容
C++ 智能指针如何使用## C++ 智能指针深度解析 智能指针是 C++11 引入的重要特性,用于自动管理动态分配的内存,避免内存泄漏和悬空指针问题。 ### 智能指针概述 **为什么需要智能指针?** - 自动释放内存,避免内存泄漏 - 防止悬空指针和双重释放 - 提供异常安全的内存管理 - 明确表达所有权语义 **RAII 原则:** - 资源获取即初始化(Resource Acquisition Is Initialization) - 资源在构造函数中获取,在析构函数中释放 - 利用对象生命周期管理资源 ### unique_ptr **基本用法:** ```cpp #include <memory> // 创建 unique_ptr std::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; } ``` **移动语义:** ```cpp // 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 变为空 ``` **自定义删除器:** ```cpp // 数组删除器 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; ``` **在容器中使用:** ```cpp std::vector<std::unique_ptr<int>> vec; // 使用 make_unique vec.push_back(std::make_unique<int>(1)); vec.push_back(std::make_unique<int>(2)); // 使用 emplace_back vec.emplace_back(std::make_unique<int>(3)); // 遍历 for (const auto& ptr : vec) { std::cout << *ptr << std::endl; } ``` ### shared_ptr **基本用法:** ```cpp // 创建 shared_ptr std::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 ``` **引用计数机制:** ```cpp 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 析构,对象被删除 ``` **自定义删除器:** ```cpp // 使用函数指针 void customDeleter(int* p) { std::cout << "Custom deleter called" << std::endl; delete p; } std::shared_ptr<int> ptr(new int(42), customDeleter); // 使用 lambda auto 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():** ```cpp 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 **基本用法:** ```cpp // 创建 weak_ptr std::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_ptr if (auto ptr = weak.lock()) { std::cout << *ptr << std::endl; } ``` **解决循环引用:** ```cpp 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 会被正确释放 } ``` **观察者模式:** ```cpp 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. 优先使用 make_unique 和 make_shared** ```cpp // 推荐 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. 避免使用裸指针管理智能指针** ```cpp // 不推荐 int* raw = new int(42); std::unique_ptr<int> ptr(raw); // 推荐 auto ptr = std::make_unique<int>(42); ``` **3. 不要从函数返回裸指针** ```cpp // 不推荐 int* getPtr() { auto ptr = std::make_unique<int>(42); return ptr.get(); // 危险! } // 推荐 std::shared_ptr<int> getPtr() { return std::make_shared<int>(42); } ``` **4. 使用智能指针管理数组** ```cpp // 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. 在函数参数中使用智能指针** ```cpp // 按值传递(增加引用计数) void process(std::shared_ptr<int> ptr) { // 使用 ptr } // 按引用传递(不增加引用计数) void process(const std::shared_ptr<int>& ptr) { // 使用 ptr } // 传递裸指针(如果函数不需要所有权) void process(int* ptr) { // 使用 ptr } ``` ### 常见陷阱 **1. 循环引用** ```cpp class A { public: std::shared_ptr<B> b; }; class B { public: std::shared_ptr<A> a; // 循环引用! }; // 解决:使用 weak_ptr class B { public: std::weak_ptr<A> a; // 正确 }; ``` **2. this 指针问题** ```cpp 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. 混合使用裸指针和智能指针** ```cpp std::shared_ptr<int> ptr = std::make_shared<int>(42); int* raw = ptr.get(); delete raw; // 错误!会导致双重释放 ``` **4. 在构造函数中传递 this** ```cpp class 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. 工厂模式** ```cpp 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. 依赖注入** ```cpp 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. 资源管理** ```cpp 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 时要注意引用计数的原子操作 - 考虑使用自定义分配器优化性能 - 理解智能指针的所有权语义,选择合适的类型
服务端 · 2月18日 17:41
C++ 网络编程基础如何实现## C++ 网络编程基础 C++ 网络编程是构建高性能网络应用的基础,涉及套接字编程、协议实现和并发处理等核心概念。 ### 套接字基础 **TCP 套接字示例:** ```cpp #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 套接字示例:** ```cpp 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 **设置非阻塞套接字:** ```cpp #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 进行多路复用:** ```cpp #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/O **epoll 服务器示例:** ```cpp #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 服务器:** ```cpp 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 管理套接字** ```cpp 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. 错误处理** ```cpp 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. 超时设置** ```cpp 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. 使用线程池处理连接** ```cpp 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 加密通信 - 注意资源泄漏,确保套接字正确关闭
服务端 · 2月18日 17:39
C++ 性能优化技巧有哪些## C++ 性能优化技巧 C++ 以其高性能著称,但要充分发挥其性能潜力,需要掌握各种优化技巧和最佳实践。 ### 编译器优化 **编译选项:** ```bash # 基本优化 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 ``` **内联函数:** ```cpp // 显式内联 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() { // 复杂计算 } ``` ### 内存优化 **数据局部性:** ```cpp // 不推荐:缓存不友好 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()]); } } ``` **内存对齐:** ```cpp // 使用 alignas 指定对齐 struct alignas(64) AlignedData { int data[16]; }; // 使用 aligned_alloc 分配对齐内存 void* alignedMemory = aligned_alloc(64, 1024); // 查询对齐要求 constexpr size_t alignment = alignof(double); ``` **避免内存碎片:** ```cpp // 推荐:对象池 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); } }; ``` ### 算法优化 **避免不必要的拷贝:** ```cpp // 不推荐:返回值拷贝 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(); // 移动构造 ``` **使用引用传递:** ```cpp // 不推荐:值传递 void process(std::vector<int> data) { // 处理数据 } // 推荐:const 引用传递 void process(const std::vector<int>& data) { // 处理数据 } // 需要修改时使用引用 void modify(std::vector<int>& data) { // 修改数据 } ``` **选择合适的容器:** ```cpp // 需要随机访问:vector std::vector<int> vec; // 需要频繁两端插入:deque std::deque<int> dq; // 需要频繁中间插入删除:list std::list<int> lst; // 需要按键查找:map/unordered_map std::map<std::string, int> mp; std::unordered_map<std::string, int> ump; // 需要快速查找:set/unordered_set std::set<int> s; std::unordered_set<int> us; ``` ### 并发优化 **使用线程池:** ```cpp 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(); } } }; ``` **使用原子操作:** ```cpp // 不推荐:使用互斥锁 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); } ``` **减少锁竞争:** ```cpp // 不推荐:全局锁 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 优化 **使用编译器内置函数:** ```cpp #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]; } } ``` **使用自动向量化:** ```cpp // 编译器会自动向量化 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]; } } ``` ### 缓存优化 **预取数据:** ```cpp #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]); } } ``` **缓存行对齐:** ```cpp // 避免伪共享 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); } }; ``` ### 性能分析 **使用性能分析工具:** ```bash # 使用 perf(Linux) perf record -g ./your_program perf report # 使用 gprof g++ -pg program.cpp -o program ./program gprof program gmon.out > analysis.txt # 使用 Valgrind 的 callgrind valgrind --tool=callgrind ./your_program kcachegrind callgrind.out.<pid> ``` **使用计时器:** ```cpp #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. 预分配内存** ```cpp // 推荐 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** ```cpp // 推荐 vec.emplace_back(arg1, arg2); // 原地构造 // 不推荐 vec.push_back(Type(arg1, arg2)); // 可能创建临时对象 ``` **3. 避免过早优化** ```cpp // 先写清晰的代码 int sum = 0; for (int val : data) { sum += val; } // 性能分析后再优化 if (isPerformanceCritical) { // 使用 SIMD 或并行化 } ``` **4. 使用 constexpr 进行编译期计算** ```cpp // 推荐 constexpr int factorial(int n) { return n <= 1 ? 1 : n * factorial(n - 1); } constexpr int result = factorial(10); // 编译期计算 ``` **5. 避免虚函数调用开销** ```cpp // 性能关键代码避免虚函数 class FastProcessor { public: void process(int value) { // 非虚函数 // 快速处理 } }; // 使用 CRTP 实现静态多态 template <typename Derived> class Base { public: void interface() { static_cast<Derived*>(this)->implementation(); } }; ``` ### 注意事项 - 性能优化应该基于实际测量,而非猜测 - 优先优化算法和数据结构,而非微优化 - 考虑可读性和可维护性,不要过度优化 - 使用性能分析工具找出真正的瓶颈 - 注意不同编译器和平台的优化差异 - 考虑使用现代 C++ 特性(如移动语义)提升性能 - 在多线程环境中注意缓存一致性和内存屏障
服务端 · 2月18日 17:38
C++ 设计模式如何实现## C++ 设计模式 设计模式是软件设计中常见问题的可重用解决方案,C++ 作为一门强大的面向对象语言,非常适合实现各种设计模式。 ### 创建型模式 **单例模式(Singleton):** ```cpp 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):** ```cpp // 抽象产品 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):** ```cpp 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):** ```cpp // 目标接口 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):** ```cpp // 组件接口 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):** ```cpp 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):** ```cpp #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):** ```cpp // 策略接口 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):** ```cpp // 命令接口 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):** ```cpp // 状态接口 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 A context.request(); // State B context.request(); // State A ``` ### 模板方法模式(Template Method) ```cpp // 抽象类 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) ```cpp // 处理者接口 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 A handlerA->handleRequest(15); // Handler B ``` ### 最佳实践 **1. 优先使用组合而非继承** ```cpp // 推荐:组合 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. 使用智能指针管理对象生命周期** ```cpp // 推荐 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 确保资源管理** ```cpp class ResourceManager { private: std::unique_ptr<Resource> resource; public: ResourceManager() : resource(std::make_unique<Resource>()) {} // 析构函数自动释放资源 }; ``` **5. 避免过度设计** ```cpp // 简单场景不需要复杂模式 int add(int a, int b) { return a + b; } // 复杂场景才使用设计模式 class Calculator { public: virtual int calculate(int a, int b) = 0; }; ```
服务端 · 2月18日 17:36
C++11/14/17/20 新特性有哪些## C++11/14/17/20 新特性 C++ 标准不断演进,每个新版本都引入了许多强大的特性,显著提升了开发效率和代码质量。 ### C++11 新特性 **自动类型推导(auto):** ```cpp // 自动推导类型 auto x = 42; // int auto y = 3.14; // double auto 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 循环:** ```cpp 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 表达式:** ```cpp // 基本语法 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; }; // 可变 lambda auto variadic = [](auto... args) { return (args + ... + 0); }; // 使用 std::vector<int> vec = {5, 15, 25}; auto it = std::find_if(vec.begin(), vec.end(), filtered); ``` **智能指针:** ```cpp #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; } ``` **右值引用与移动语义:** ```cpp 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:** ```cpp // C++11 之前 int* ptr1 = NULL; void func(int* ptr); void func(int value); func(NULL); // 歧义,可能调用 func(int) // C++11 int* ptr2 = nullptr; func(nullptr); // 明确调用 func(int*) ``` **constexpr:** ```cpp // 编译期常量 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.0 ``` ### C++14 新特性 **泛型 lambda:** ```cpp // C++11 auto add = [](int a, int b) { return a + b; }; // C++14 - 泛型 lambda auto genericAdd = [](auto a, auto b) { return a + b; }; auto result1 = genericAdd(10, 20); // int auto result2 = genericAdd(3.14, 2.71); // double ``` **变量模板:** ```cpp template <typename T> constexpr T pi = T(3.1415926535897932385); // 使用 double d = pi<double>; float f = pi<float>; ``` **二进制字面量:** ```cpp int binary = 0b1010; // 10 int octal = 012; // 10 int hex = 0xA; // 10 ``` **函数返回类型推导:** ```cpp // C++11 auto 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:** ```cpp // C++11 auto ptr = std::unique_ptr<int>(new int(42)); // C++14 auto ptr = std::make_unique<int>(42); ``` ### C++17 新特性 **结构化绑定:** ```cpp 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++17 for (const auto& [key, value] : myMap) { std::cout << key << ": " << value << std::endl; } // 元组解包 auto [x, y, z] = std::make_tuple(1, 2.0, "three"); ``` **if constexpr:** ```cpp 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); // 20 process(3.14); // 1.57 ``` **std::optional:** ```cpp #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:** ```cpp #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:** ```cpp #include <any> std::any value = 42; value = 3.14; value = "Hello"; // 访问 if (value.type() == typeid(int)) { int intValue = std::any_cast<int>(value); } ``` **折叠表达式:** ```cpp // C++17 template <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:** ```cpp #include <string_view> void printString(std::string_view str) { std::cout << str << std::endl; } // 使用 std::string str = "Hello"; const char* cstr = "World"; printString(str); // OK printString(cstr); // OK printString("Test"); // OK,无需创建临时 string 对象 ``` ### C++20 新特性 **概念(Concepts):** ```cpp #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):** ```cpp 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):** ```cpp #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):** ```cpp #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):** ```cpp // 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.cpp import math; int main() { int result = add(10, 20); return 0; } ``` **std::format:** ```cpp #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 进行类型推导** ```cpp // 推荐 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. 使用智能指针管理资源** ```cpp // 推荐 auto ptr = std::make_unique<Resource>(); // 不推荐 Resource* ptr = new Resource(); ``` **3. 使用 nullptr 代替 NULL** ```cpp // 推荐 int* ptr = nullptr; // 不推荐 int* ptr = NULL; ``` **4. 使用 constexpr 进行编译期计算** ```cpp // 推荐 constexpr int size = 1024; // 不推荐 const int size = 1024; ``` **5. 使用范围 for 循环** ```cpp // 推荐 for (const auto& val : vec) { std::cout << val << std::endl; } // 不推荐 for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << std::endl; } ```
服务端 · 2月18日 17:36
C++ 模板的特化与偏特化如何使用## C++ 模板的特化与偏特化 模板是 C++ 泛型编程的核心机制,而模板特化和偏特化则为模板提供了更精细的控制能力,允许为特定类型提供定制化的实现。 ### 模板基础 **函数模板:** ```cpp template <typename T> T max(T a, T b) { return (a > b) ? a : b; } // 使用 int result = max(10, 20); // T = int double result2 = max(3.14, 2.71); // T = double ``` **类模板:** ```cpp 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):** 为所有模板参数提供具体类型,完全替换模板定义。 ```cpp // 通用模板 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: 42 Vector<bool> boolVec; boolVec.push(true); // 输出: Bool push: true ``` **函数模板特化:** ```cpp // 通用模板 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 compare compare("hello", "world"); // 输出: String compare ``` ### 模板偏特化 偏特化(Partial Specialization)只适用于类模板,允许部分指定模板参数。 **基本示例:** ```cpp // 通用模板:两个类型参数 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) ``` ### 指针和引用的偏特化 ```cpp // 通用模板 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 type std::cout << TypeInfo<int*>::name() << std::endl; // Pointer type std::cout << TypeInfo<int&>::name() << std::endl; // Reference type std::cout << TypeInfo<const int>::name() << std::endl; // Const type ``` ### SFINAE(替换失败并非错误) SFINAE 是模板元编程的重要技术,允许在模板参数替换失败时排除该模板,而不是产生编译错误。 **基本示例:** ```cpp // 检查类型是否有 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>::type process(T container) { std::cout << "Container has value_type" << std::endl; } template <typename T> typename std::enable_if<!has_value_type<T>::value, void>::type process(T value) { std::cout << "Type doesn't have value_type" << std::endl; } // 使用 std::vector<int> vec; process(vec); // Container has value_type int x = 42; process(x); // Type doesn't have value_type ``` **C++17 的 if constexpr:** ```cpp 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 type int num = 42; printTypeInfo(num); // Integral type double d = 3.14; printTypeInfo(d); // Floating point type ``` ### 模板元编程 **编译期计算:** ```cpp // 编译期计算阶乘 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 ``` **编译期判断:** ```cpp 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>` 头文件,提供了丰富的类型萃取工具。 **常用类型萃取:** ```cpp #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 int using 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>); ``` ### 实际应用示例 **智能指针的删除器特化:** ```cpp 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]); ``` **容器的优化特化:** ```cpp 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. 优先使用类型萃取而非手动特化** ```cpp // 推荐 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 进行编译期计算** ```cpp // C++11/14 template <int N> struct Factorial { static constexpr int value = N * Factorial<N - 1>::value; }; // C++17 constexpr int factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1); } ``` **3. 使用概念(C++20)约束模板** ```cpp 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); // OK add(3.14, 2.71); // 编译错误 ``` **4. 避免过度复杂的模板元编程** ```cpp // 不推荐:过度复杂 template <typename T> struct ComplexMetaProgramming { // 大量嵌套模板 }; // 推荐:简洁明了 template <typename T> void simpleFunction(T value) { // 简单直接的实现 } ``` ### 注意事项 - 函数模板不支持偏特化,只能全特化 - 特化版本必须在主模板之后声明 - 特化版本必须与主模板的接口一致 - SFINAE 可能导致编译错误信息难以理解 - 过度使用模板特化可能导致代码膨胀 - C++20 的概念可以替代部分 SFINAE 用法,提供更好的可读性
服务端 · 2月18日 17:35
C++ 异常处理机制如何使用## C++ 异常处理机制 C++ 异常处理提供了一种结构化的错误处理方式,允许程序在运行时检测和处理错误,而不会导致程序崩溃。 ### 异常处理基础 **基本语法:** ```cpp #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 ``` **使用标准异常:** ```cpp #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; } } ``` ### 自定义异常类 **基本自定义异常:** ```cpp 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"); } ``` **带错误代码的异常:** ```cpp 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 规范:** ```cpp // C++11 之前的异常规范(已弃用) void oldFunction() throw(std::runtime_error) { // 可能抛出 runtime_error } // C++11 的 noexcept void safeFunction() noexcept { // 保证不抛出异常 } // 条件 noexcept template <typename T> void conditionalNoexcept(T&& value) noexcept(std::is_nothrow_move_constructible_v<T>) { // 根据 T 的移动构造函数是否 noexcept 来决定 } ``` **noexcept 的作用:** - 优化编译器生成的代码 - 允许标准库选择更高效的实现(如 vector 移动) - 提供更好的错误处理保证 ### RAII 与异常安全 **异常安全级别:** **1. 基本保证(Basic Guarantee):** ```cpp 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):** ```cpp 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):** ```cpp class NoThrowExample { private: std::unique_ptr<int> ptr; public: void reset() noexcept { ptr.reset(); // unique_ptr::reset 是 noexcept } }; ``` ### 智能指针与异常安全 **使用智能指针确保异常安全:** ```cpp // 不推荐:手动管理内存 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 与异常安全:** ```cpp std::mutex mtx; void threadSafeOperation() { std::lock_guard<std::mutex> lock(mtx); // 临界区代码 // 即使抛出异常,锁也会自动释放 riskyOperation(); } ``` ### 异常捕获与重新抛出 **捕获并重新抛出:** ```cpp 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); } } ``` ### 异常与构造函数/析构函数 **构造函数中的异常:** ```cpp 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; } }; ``` **析构函数中的异常:** ```cpp class MyClass { private: std::unique_ptr<int> ptr; public: ~MyClass() noexcept { // 析构函数不应该抛出异常 try { cleanup(); } catch (...) { // 吞掉异常或记录日志 std::cerr << "Exception in destructor" << std::endl; } } void cleanup() { // 清理逻辑 } }; ``` ### 异常与函数指针 **异常规范与函数指针:** ```cpp // noexcept 函数指针 using NoThrowFunction = void(*)() noexcept; void safeFunction() noexcept { // 不抛出异常 } void unsafeFunction() { // 可能抛出异常 } NoThrowFunction func1 = safeFunction; // OK // NoThrowFunction func2 = unsafeFunction; // 编译错误 ``` ### 最佳实践 **1. 按值抛出,按引用捕获** ```cpp // 推荐 throw MyException("Error message"); try { riskyOperation(); } catch (const MyException& e) { // 按引用捕获 std::cerr << e.what() << std::endl; } // 不推荐 throw new MyException("Error message"); // 不要抛出指针 ``` **2. 捕获最具体的异常** ```cpp try { riskyOperation(); } catch (const std::invalid_argument& e) { // 处理特定异常 } catch (const std::runtime_error& e) { // 处理运行时错误 } catch (const std::exception& e) { // 处理其他标准异常 } catch (...) { // 处理未知异常 } ``` **3. 使用 RAII 确保资源释放** ```cpp 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. 异常只用于异常情况** ```cpp // 推荐:异常用于真正的错误 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. 提供有意义的错误信息** ```cpp 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 作为异常的替代方案 - 在多线程环境中,异常只在当前线程中传播
服务端 · 2月18日 17:34
C++ 并发编程与多线程如何实现## C++ 并发编程与多线程 C++11 引入了标准化的多线程支持,提供了丰富的并发编程工具,包括线程、互斥锁、条件变量、原子操作等。 ### 线程基础 **创建线程:** ```cpp #include <thread> #include <iostream> void hello() { std::cout << "Hello from thread!" << std::endl; } int main() { // 创建线程 std::thread t(hello); // 等待线程完成 t.join(); return 0; } ``` **带参数的线程:** ```cpp 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 表达式:** ```cpp int main() { int value = 42; std::thread t([value]() { std::cout << "Value: " << value << std::endl; }); t.join(); return 0; } ``` ### 互斥锁(Mutex) **基本使用:** ```cpp #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:** ```cpp 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:** ```cpp 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) **基本使用:** ```cpp #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) **基本类型:** ```cpp #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; } ``` **内存顺序:** ```cpp 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):** ```cpp 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:** ```cpp #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) **基本使用:** ```cpp #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:** ```cpp #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:** ```cpp #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; } ``` ### 线程池实现 **简单线程池:** ```cpp #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. 避免数据竞争** ```cpp // 错误:数据竞争 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. 避免死锁** ```cpp // 错误:可能导致死锁 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::lock void 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 管理锁** ```cpp // 推荐 void safeFunction() { std::lock_guard<std::mutex> lock(mtx); // 临界区代码 } // 自动释放锁 // 不推荐 void unsafeFunction() { mtx.lock(); // 临界区代码 mtx.unlock(); // 可能忘记或异常导致未释放 } ``` **4. 优先使用原子操作** ```cpp // 推荐:原子操作 std::atomic<int> counter(0); ++counter; // 不推荐:互斥锁(对于简单操作) std::mutex mtx; int counter = 0; { std::lock_guard<std::mutex> lock(mtx); ++counter; } ``` ### 注意事项 - 始终确保线程被正确 join 或 detach - 避免在析构函数中使用互斥锁 - 注意条件变量的虚假唤醒 - 合理选择内存顺序,避免过度使用 memory_order_seq_cst - 避免过度细粒度的锁,可能导致性能下降 - 使用线程池管理大量短期任务 - 注意异常安全,确保资源正确释放 - 避免在多线程环境中使用全局变量
服务端 · 2月18日 17:34
C++ 内存管理与内存泄漏如何避免## C++ 内存管理与内存泄漏 C++ 提供了强大的内存管理能力,但也要求开发者对内存生命周期有清晰的认识。不当的内存管理会导致内存泄漏、悬空指针、重复释放等严重问题。 ### C++ 内存区域 **1. 栈(Stack)** - 存储局部变量、函数参数、返回地址 - 自动分配和释放 - 大小有限(通常几 MB) - 分配速度快 **2. 堆(Heap)** - 动态分配的内存 - 手动管理(new/delete)或智能指针管理 - 大小受限于系统可用内存 - 分配速度较慢 **3. 全局/静态区** - 存储全局变量、静态变量 - 程序启动时分配,结束时释放 - 生命周期贯穿整个程序 **4. 常量区** - 存储字符串常量、const 变量 - 只读,不可修改 **5. 代码区** - 存储程序二进制代码 - 只读 ### 内存泄漏的原因 **1. 忘记释放内存** ```cpp void leakExample() { int* ptr = new int(42); // 忘记 delete ptr; } ``` **2. 异常导致跳过释放** ```cpp void leakWithException() { int* ptr = new int(42); someFunctionThatThrows(); // 如果抛出异常,ptr 不会被释放 delete ptr; } ``` **3. 循环引用** ```cpp 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. 不当的指针赋值** ```cpp void lostPointer() { int* ptr = new int(42); ptr = new int(100); // 第一个分配的内存泄漏 delete ptr; } ``` ### 检测内存泄漏 **1. Valgrind(Linux)** ```bash valgrind --leak-check=full --show-leak-kinds=all ./your_program ``` **2. AddressSanitizer(ASan)** ```bash g++ -fsanitize=address -g your_program.cpp -o your_program ./your_program ``` **3. Visual Studio 调试器** - 使用 CRT 调试堆 - 在代码开头添加: ```cpp #define _CRTDBG_MAP_ALLOC #include <crtdbg.h> _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); ``` **4. 自定义内存跟踪** ```cpp 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. 使用智能指针** ```cpp // 不推荐 void badExample() { Resource* res = new Resource(); // 容易忘记 delete } // 推荐 void goodExample() { auto res = std::make_unique<Resource>(); // 自动释放 } ``` **2. 遵循 RAII 原则** ```cpp 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. 使用标准容器** ```cpp // 不推荐 void badContainer() { int* arr = new int[100]; // 处理数组 delete[] arr; } // 推荐 void goodContainer() { std::vector<int> arr(100); // 自动管理内存 } ``` **4. 正确处理异常** ```cpp // 不推荐 void badException() { int* ptr = new int(42); riskyOperation(); // 可能抛出异常 delete ptr; } // 推荐 void goodException() { auto ptr = std::make_unique<int>(42); riskyOperation(); // 即使抛出异常,ptr 也会被正确释放 } ``` ### 内存对齐 **为什么需要内存对齐:** - CPU 访问对齐的内存更快 - 某些架构要求特定类型必须对齐 - 避免性能下降或程序崩溃 **对齐方式:** ```cpp // 使用 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); ``` ### 内存池 **内存池的优点:** - 减少内存碎片 - 提高分配/释放速度 - 减少系统调用次数 **简单实现:** ```cpp 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. 优先使用栈内存** ```cpp // 优先 void stackPreferred() { int value = 42; process(value); } // 仅在必要时使用堆 void heapWhenNeeded() { auto value = std::make_unique<int>(42); process(*value); } ``` **2. 使用标准库容器** ```cpp std::vector<int> vec; // 自动管理内存 std::string str; // 自动管理内存 std::map<int, int> map; // 自动管理内存 ``` **3. 避免裸指针** ```cpp // 不推荐 int* ptr = new int(42); // ... 使用 ptr delete ptr; // 推荐 auto ptr = std::make_unique<int>(42); // ... 使用 ptr // 自动释放 ``` **4. 使用 const 正确性** ```cpp void process(const std::vector<int>& data); // 避免拷贝 void modify(std::vector<int>& data); // 明确表示会修改 ``` **5. 定期进行内存分析** ```bash # 使用 Valgrind 检测内存泄漏 valgrind --leak-check=full --show-leak-kinds=all ./your_program # 使用 AddressSanitizer g++ -fsanitize=address -g your_program.cpp -o your_program ./your_program ``` ### 常见错误 **1. 重复释放** ```cpp int* ptr = new int(42); delete ptr; delete ptr; // 未定义行为 ``` **2. 释放未分配的内存** ```cpp int* ptr; delete ptr; // 未定义行为 ``` **3. 数组 new/delete 不匹配** ```cpp int* arr = new int[10]; delete arr; // 错误,应该使用 delete[] arr ``` **4. 栈内存使用 delete** ```cpp int value = 42; int* ptr = &value; delete ptr; // 错误,不能释放栈内存 ``` **5. 悬空指针** ```cpp int* ptr = new int(42); delete ptr; *ptr = 100; // 未定义行为,悬空指针 ```
服务端 · 2月18日 17:34
C++ STL 容器与算法如何使用## C++ STL 容器与算法 C++ 标准模板库(STL)提供了丰富的容器和算法,是 C++ 编程的重要组成部分。熟练掌握 STL 可以显著提高开发效率和代码质量。 ### 序列容器 **std::vector** - 动态数组,连续内存存储 - 支持随机访问,O(1) 时间复杂度 - 尾部插入和删除效率高 O(1),中间插入删除 O(n) - 自动扩容,通常容量翻倍 ```cpp #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 大 ```cpp #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) - 不支持随机访问 - 额外内存开销(每个节点两个指针) ```cpp #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) - 键唯一 ```cpp #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) ```cpp #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) ```cpp #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 实现 ```cpp #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 实现 ```cpp #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** - 优先级队列 - 默认大顶堆 ```cpp #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 算法 **排序算法:** ```cpp #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; } ``` **查找算法:** ```cpp 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; } ``` **变换算法:** ```cpp 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; } ``` **数值算法:** ```cpp #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; } ``` ### 迭代器 **迭代器分类:** - 输入迭代器:只读,单向 - 输出迭代器:只写,单向 - 前向迭代器:读写,单向 - 双向迭代器:读写,双向 - 随机访问迭代器:读写,随机访问 ```cpp 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; } ``` ### 函数对象与 Lambda **Lambda 表达式:** ```cpp 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:** ```cpp #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. 选择合适的容器** ```cpp // 需要随机访问,频繁尾部插入 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. 预分配空间** ```cpp std::vector<int> vec; vec.reserve(1000); // 预先分配空间,避免多次重新分配 ``` **3. 使用 emplace 代替 push** ```cpp std::vector<std::pair<int, int>> vec; // 推荐 vec.emplace_back(1, 2); // 原地构造 // 不推荐 vec.push_back(std::make_pair(1, 2)); // 可能产生临时对象 ``` **4. 使用移动语义** ```cpp std::vector<std::string> vec; std::string str = "Hello"; vec.push_back(std::move(str)); // 移动而非拷贝 ``` **5. 使用算法代替循环** ```cpp 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: 最差(分散内存)
服务端 · 2月18日 17:34