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