服务端2月18日 17:41
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 时要注意引用计数的原子操作
- 考虑使用自定义分配器优化性能
- 理解智能指针的所有权语义,选择合适的类型标签
C++
C++ 是一种通用的、静态类型的编程语言,它具有高效性、灵活性和可移植性等特点。C++ 基于 C 语言,同时支持面向对象编程和泛型编程,可以用于开发各种类型的应用程序,如系统软件、游戏、桌面应用程序、移动应用程序等。 C++ 的主要特点包括: 高效性:C++ 是一种编译型语言,可以生成高效的本地代码,在性能要求高的应用程序中得到广泛应用; 面向对象编程:C++ 支持面向对象编程,包括封装、继承、多态等特性,使得开发人员可以更加灵活和高效地构建复杂的软件系统; 泛型编程:C++ 支持泛型编程,包括模板和泛型算法等特性,使得开发人员可以编写可重用的代码和算法; 可移植性:C++ 可以在多种平台和操作系统上运行,具有很高的可移植性; 标准化:C++ 有一个国际标准,称为 C++ 标准,规范了语言的语法、语义和库函数等方面,使得 C++ 的代码更加规范和可靠。 C++ 作为一种通用的编程语言,可以用于多种应用场景。在系统软件开发中,C++ 可以用于操作系统内核、驱动程序、网络协议栈等方面;在游戏开发中,C++ 可以用于游戏引擎、物理引擎、图形渲染等方面;在桌面应用程序和移动应用程序开发中,C++ 可以用于开发各种类型的应用程序,如音频和视频编辑、图像处理、数据库管理等方面。 如果您想要成为一名优秀的程序员,C++ 是一个非常有用的编程语言,它具有广泛的应用场景和丰富的编程资源,可以帮助您更加高效和灵活地解决实际问题。

服务端2月18日 17:39
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:38
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:36
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:35
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:34
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
C++ 移动语义与完美转发如何使用## C++ 移动语义与完美转发
C++11 引入的移动语义和完美转发是现代 C++ 性能优化的核心特性,它们通过减少不必要的拷贝操作显著提升了程序性能。
### 移动语义
**左值与右值:**
- 左值(lvalue):有名字、可以取地址的对象,通常在赋值运算符左边
- 右值(rvalue):临时对象、字面量、即将销毁的对象,通常在赋值运算符右边
```cpp
int a = 10; // a 是左值,10 是右值
int b = a + 5; // b 是左值,a + 5 是右值
```
**std::move:**
std::move 将左值转换为右值引用,启用移动语义。
```cpp
std::string str1 = "Hello";
std::string str2 = std::move(str1); // 移动构造,str1 变为空
// str1 现在处于有效但未指定的状态
```
### 移动构造函数与移动赋值运算符
**移动构造函数:**
```cpp
class MyString {
private:
char* data;
size_t size;
public:
// 普通构造函数
MyString(const char* str = "") {
size = strlen(str);
data = new char[size + 1];
strcpy(data, str);
}
// 拷贝构造函数
MyString(const MyString& other) {
size = other.size;
data = new char[size + 1];
strcpy(data, other.data);
std::cout << "Copy constructor called" << std::endl;
}
// 移动构造函数
MyString(MyString&& other) noexcept {
data = other.data;
size = other.size;
other.data = nullptr;
other.size = 0;
std::cout << "Move constructor called" << std::endl;
}
// 拷贝赋值运算符
MyString& operator=(const MyString& other) {
if (this != &other) {
delete[] data;
size = other.size;
data = new char[size + 1];
strcpy(data, other.data);
}
std::cout << "Copy assignment called" << std::endl;
return *this;
}
// 移动赋值运算符
MyString& operator=(MyString&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
size = other.size;
other.data = nullptr;
other.size = 0;
}
std::cout << "Move assignment called" << std::endl;
return *this;
}
~MyString() {
delete[] data;
}
};
```
### 移动语义的优势
**性能提升:**
```cpp
// 不使用移动语义
std::vector<std::string> createVector() {
std::vector<std::string> vec;
vec.push_back("Hello");
vec.push_back("World");
return vec; // C++11 之前会进行深拷贝
}
// 使用移动语义
std::vector<std::string> createVectorMove() {
std::vector<std::string> vec;
vec.push_back("Hello");
vec.push_back("World");
return vec; // C++11 之后会进行移动,避免深拷贝
}
// 使用
auto vec = createVectorMove(); // 移动构造,无拷贝
```
**容器操作优化:**
```cpp
std::vector<MyString> vec;
vec.reserve(10);
MyString str1("Hello");
vec.push_back(str1); // 拷贝构造
vec.push_back(std::move(str1)); // 移动构造,更快
vec.emplace_back("World"); // 原地构造,最快
```
### 完美转发
完美转发允许函数模板将其参数完美地转发给其他函数,保持参数的值类别(左值或右值)。
**std::forward:**
```cpp
template <typename T>
void wrapper(T&& arg) {
target(std::forward<T>(arg)); // 完美转发
}
void target(const std::string& str) {
std::cout << "Lvalue reference: " << str << std::endl;
}
void target(std::string&& str) {
std::cout << "Rvalue reference: " << str << std::endl;
}
// 使用
std::string str = "Hello";
wrapper(str); // 转发为左值引用
wrapper(std::string("World")); // 转发为右值引用
```
**引用折叠规则:**
- T& & → T&
- T& && → T&
- T&& & → T&
- T&& && → T&&
### 万能引用
万能引用(Universal Reference)是使用 T&& 声明的引用,可以绑定到左值或右值。
```cpp
template <typename T>
void process(T&& arg) {
// arg 是万能引用
if constexpr (std::is_lvalue_reference_v<T>) {
std::cout << "Lvalue reference" << std::endl;
} else {
std::cout << "Rvalue reference" << std::endl;
}
}
// 使用
int x = 42;
process(x); // T = int&,绑定到左值
process(42); // T = int,绑定到右值
```
**注意:** 只有在类型推导上下文中 T&& 才是万能引用,否则是右值引用。
```cpp
template <typename T>
class MyClass {
void process(T&& arg); // 右值引用,不是万能引用
};
template <typename T>
void process(T&& arg); // 万能引用
```
### 实际应用示例
**智能指针工厂函数:**
```cpp
template <typename T, typename... Args>
std::unique_ptr<T> makeUnique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
// 使用
class Widget {
public:
Widget(int x, double y) : x_(x), y_(y) {}
private:
int x_;
double y_;
};
auto widget = makeUnique<Widget>(10, 3.14);
```
**线程任务包装器:**
```cpp
template <typename F, typename... Args>
auto createTask(F&& f, Args&&... args) {
return std::async(std::forward<F>(f), std::forward<Args>(args)...);
}
// 使用
void task(int x, const std::string& str) {
std::cout << "Task: " << x << ", " << str << std::endl;
}
auto future = createTask(task, 42, "Hello");
```
**容器插入优化:**
```cpp
template <typename Container, typename T>
void insert(Container& container, T&& value) {
container.push_back(std::forward<T>(value));
}
// 使用
std::vector<std::string> vec;
std::string str = "Hello";
insert(vec, str); // 拷贝插入
insert(vec, std::string("World")); // 移动插入
```
### noexcept 规范
移动操作应该标记为 noexcept,以便标准库在重新分配时使用移动而非拷贝。
```cpp
class MyClass {
public:
MyClass(MyClass&& other) noexcept {
// 移动构造实现
}
MyClass& operator=(MyClass&& other) noexcept {
// 移动赋值实现
return *this;
}
};
```
### 最佳实践
**1. 优先使用移动语义**
```cpp
// 推荐
std::string result = std::move(tempString);
// 不推荐
std::string result = tempString; // 不必要的拷贝
```
**2. 使用 emplace 系列函数**
```cpp
// 推荐
vec.emplace_back(args...); // 原地构造
// 不推荐
vec.push_back(Type(args...)); // 可能产生临时对象
```
**3. 正确使用 std::forward**
```cpp
template <typename T>
void wrapper(T&& arg) {
// 正确
target(std::forward<T>(arg));
// 错误
target(arg); // 总是左值
target(std::move(arg)); // 总是右值
}
```
**4. 移动后对象的状态**
```cpp
std::string str1 = "Hello";
std::string str2 = std::move(str1);
// str1 处于有效但未指定的状态
// 可以安全地赋值或销毁
str1 = "New value"; // OK
std::cout << str1.length(); // OK,但值未定义
```
**5. 避免对 const 对象使用 std::move**
```cpp
const std::string str = "Hello";
std::string str2 = std::move(str); // 不会移动,会拷贝
```
### 常见错误
**1. 滥用 std::move**
```cpp
// 错误
std::string str = "Hello";
std::cout << std::move(str); // 不必要,可能影响性能
// 正确
std::cout << str;
```
**2. 移动后使用对象**
```cpp
std::string str1 = "Hello";
std::string str2 = std::move(str1);
std::cout << str1; // 未定义行为
```
**3. 返回局部变量时不使用 std::move**
```cpp
// 错误
std::string createString() {
std::string str = "Hello";
return std::move(str); // 阻止 RVO
}
// 正确
std::string createString() {
std::string str = "Hello";
return str; // 编译器会自动优化
}
```
**4. 忘记 noexcept**
```cpp
// 不推荐
MyClass(MyClass&& other); // 没有 noexcept
// 推荐
MyClass(MyClass&& other) noexcept; // 允许标准库优化
```
### 性能对比
```cpp
#include <chrono>
#include <vector>
class BigObject {
private:
std::vector<int> data;
public:
BigObject(size_t size) : data(size) {}
BigObject(const BigObject& other) : data(other.data) {
std::cout << "Copy" << std::endl;
}
BigObject(BigObject&& other) noexcept : data(std::move(other.data)) {
std::cout << "Move" << std::endl;
}
};
void benchmark() {
const size_t size = 1000000;
// 拷贝性能测试
auto start = std::chrono::high_resolution_clock::now();
std::vector<BigObject> vec1;
for (size_t i = 0; i < 100; ++i) {
BigObject obj(size);
vec1.push_back(obj); // 拷贝
}
auto end = std::chrono::high_resolution_clock::now();
auto copy_time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
// 移动性能测试
start = std::chrono::high_resolution_clock::now();
std::vector<BigObject> vec2;
for (size_t i = 0; i < 100; ++i) {
BigObject obj(size);
vec2.push_back(std::move(obj)); // 移动
}
end = std::chrono::high_resolution_clock::now();
auto move_time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Copy time: " << copy_time.count() << " ms" << std::endl;
std::cout << "Move time: " << move_time.count() << " ms" << std::endl;
}
```
移动语义和完美转发是现代 C++ 的重要组成部分,正确使用它们可以显著提升程序性能,特别是在处理大型对象和容器时。服务端2月18日 17:33
C++ 指针与引用的区别是什么## C++ 指针与引用的区别
C++ 中指针和引用是两个重要的概念,它们在语法和使用上有很多相似之处,但在底层实现和特性上存在显著差异。
### 主要区别
**1. 内存占用**
- 指针:占用 4 字节(32 位系统)或 8 字节(64 位系统)的内存空间
- 引用:不占用额外内存空间,只是变量的别名
**2. 初始化要求**
- 指针:可以不初始化,声明时可以不指向任何有效地址
- 引用:必须在声明时初始化,且一旦绑定就不能改变
**3. 空值处理**
- 指针:可以设置为 nullptr 或 NULL,表示不指向任何对象
- 引用:不能为空,必须始终引用一个有效的对象
**4. 重新赋值**
- 指针:可以重新赋值,指向不同的对象
- 引用:一旦初始化后,不能改变引用的对象
**5. 运算符**
- 指针:使用 * 和 -> 运算符访问指向的对象
- 引用:直接使用变量名访问,无需额外运算符
**6. 多级引用**
- 指针:支持多级指针(如 int**)
- 引用:不支持多级引用
### 使用场景
**指针适用于:**
- 需要动态内存分配
- 需要重新赋值指向不同对象
- 需要表示"无对象"的状态
- 实现数据结构(链表、树等)
**引用适用于:**
- 函数参数传递,避免拷贝开销
- 函数返回值,支持链式调用
- 运算符重载
- 确保参数不为空的情况
### 代码示例
```cpp
// 指针示例
int* ptr = nullptr;
int a = 10;
ptr = &a;
*ptr = 20; // a 的值变为 20
// 引用示例
int b = 10;
int& ref = b;
ref = 30; // b 的值变为 30
// 函数参数示例
void swap(int* x, int* y) {
int temp = *x;
*x = *y;
*y = temp;
}
void swap(int& x, int& y) {
int temp = x;
x = y;
y = temp;
}
```
### 注意事项
- 在现代 C++ 中,优先使用引用和智能指针,避免使用裸指针
- 引用在函数参数中使用时,可以提供更好的代码可读性
- 指针需要手动管理内存,容易导致内存泄漏,建议使用智能指针(std::unique_ptr, std::shared_ptr)服务端2月18日 17:33
C++ 多态的实现机制有哪些## C++ 多态的实现机制
多态是面向对象编程的核心特性之一,C++ 通过虚函数和继承机制实现了编译时多态和运行时多态。
### 多态的类型
**1. 编译时多态(静态多态)**
- 函数重载
- 运算符重载
- 模板(泛型编程)
**2. 运行时多态(动态多态)**
- 虚函数
- 纯虚函数
- 抽象类
### 虚函数实现多态
**基本示例:**
```cpp
class Animal {
public:
virtual void makeSound() {
std::cout << "Animal makes a sound" << std::endl;
}
virtual ~Animal() {}
};
class Dog : public Animal {
public:
void makeSound() override {
std::cout << "Dog barks" << std::endl;
}
};
class Cat : public Animal {
public:
void makeSound() override {
std::cout << "Cat meows" << std::endl;
}
};
// 使用多态
void animalSound(Animal* animal) {
animal->makeSound(); // 动态绑定
}
int main() {
Dog dog;
Cat cat;
animalSound(&dog); // 输出: Dog barks
animalSound(&cat); // 输出: Cat meows
return 0;
}
```
### 纯虚函数与抽象类
**纯虚函数:**
```cpp
class Shape {
public:
virtual double area() = 0; // 纯虚函数
virtual double perimeter() = 0;
virtual ~Shape() {} // 虚析构函数
};
class Rectangle : public Shape {
private:
double width;
double height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
double area() override {
return width * height;
}
double perimeter() override {
return 2 * (width + height);
}
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double area() override {
return 3.14159 * radius * radius;
}
double perimeter() override {
return 2 * 3.14159 * radius;
}
};
// 使用
void printShapeInfo(Shape* shape) {
std::cout << "Area: " << shape->area() << std::endl;
std::cout << "Perimeter: " << shape->perimeter() << std::endl;
}
int main() {
Rectangle rect(5, 3);
Circle circle(2);
printShapeInfo(&rect); // Rectangle 的实现
printShapeInfo(&circle); // Circle 的实现
return 0;
}
```
### 虚析构函数
**为什么需要虚析构函数:**
```cpp
class Base {
public:
virtual ~Base() {
std::cout << "Base destructor" << std::endl;
}
};
class Derived : public Base {
private:
int* data;
public:
Derived() : data(new int[100]) {}
~Derived() {
delete[] data;
std::cout << "Derived destructor" << std::endl;
}
};
// 正确使用
Base* ptr = new Derived();
delete ptr; // 正确调用 Derived 和 Base 的析构函数
// 如果 Base 的析构函数不是虚函数
class BaseNoVirtual {
public:
~BaseNoVirtual() { // 非虚析构函数
std::cout << "BaseNoVirtual destructor" << std::endl;
}
};
class DerivedNoVirtual : public BaseNoVirtual {
private:
int* data;
public:
DerivedNoVirtual() : data(new int[100]) {}
~DerivedNoVirtual() {
delete[] data;
std::cout << "DerivedNoVirtual destructor" << std::endl;
}
};
// 错误使用
BaseNoVirtual* ptr2 = new DerivedNoVirtual();
delete ptr2; // 只调用 BaseNoVirtual 的析构函数,内存泄漏!
```
### override 关键字
**使用 override 确保正确重写:**
```cpp
class Base {
public:
virtual void func1() {}
virtual void func2(int x) {}
};
class Derived : public Base {
public:
void func1() override { // 正确重写
std::cout << "Derived func1" << std::endl;
}
// void func2() override; // 编译错误:参数不匹配
// void func3() override; // 编译错误:基类没有 func3
};
```
### final 关键字
**阻止进一步重写或继承:**
```cpp
class Base {
public:
virtual void func() final { // 不能被重写
std::cout << "Base func" << std::endl;
}
};
class Derived1 : public Base {
public:
// void func() override; // 编译错误:func 是 final
};
class FinalClass final { // 不能被继承
public:
void method() {}
};
// class Derived2 : public FinalClass {}; // 编译错误:FinalClass 是 final
```
### 运行时类型识别(RTTI)
**dynamic_cast:**
```cpp
class Animal {
public:
virtual ~Animal() {}
};
class Dog : public Animal {
public:
void bark() {
std::cout << "Woof!" << std::endl;
}
};
class Cat : public Animal {
public:
void meow() {
std::cout << "Meow!" << std::endl;
}
};
void processAnimal(Animal* animal) {
if (Dog* dog = dynamic_cast<Dog*>(animal)) {
dog->bark();
} else if (Cat* cat = dynamic_cast<Cat*>(animal)) {
cat->meow();
}
}
// 使用
Dog dog;
Cat cat;
processAnimal(&dog); // 输出: Woof!
processAnimal(&cat); // 输出: Meow!
```
**typeid:**
```cpp
#include <typeinfo>
class Base {
public:
virtual ~Base() {}
};
class Derived : public Base {};
int main() {
Base* base = new Derived();
std::cout << "Type name: " << typeid(*base).name() << std::endl;
std::cout << "Is Derived: " << (typeid(*base) == typeid(Derived)) << std::endl;
delete base;
return 0;
}
```
### 多态的实际应用
**策略模式:**
```cpp
class SortStrategy {
public:
virtual void sort(std::vector<int>& data) = 0;
virtual ~SortStrategy() {}
};
class BubbleSort : public SortStrategy {
public:
void sort(std::vector<int>& data) override {
std::cout << "Using Bubble Sort" << std::endl;
// 冒泡排序实现
}
};
class QuickSort : public SortStrategy {
public:
void sort(std::vector<int>& data) override {
std::cout << "Using Quick Sort" << std::endl;
// 快速排序实现
}
};
class Sorter {
private:
SortStrategy* strategy;
public:
void setStrategy(SortStrategy* s) {
strategy = s;
}
void sort(std::vector<int>& data) {
strategy->sort(data);
}
};
// 使用
Sorter sorter;
BubbleSort bubbleSort;
QuickSort quickSort;
std::vector<int> data = {5, 2, 8, 1, 9};
sorter.setStrategy(&bubbleSort);
sorter.sort(data); // 使用冒泡排序
sorter.setStrategy(&quickSort);
sorter.sort(data); // 使用快速排序
```
**观察者模式:**
```cpp
class Observer {
public:
virtual void update(const std::string& message) = 0;
virtual ~Observer() {}
};
class Subject {
private:
std::vector<Observer*> observers;
public:
void attach(Observer* observer) {
observers.push_back(observer);
}
void detach(Observer* observer) {
observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
}
void notify(const std::string& message) {
for (auto observer : observers) {
observer->update(message);
}
}
};
class EmailObserver : public Observer {
public:
void update(const std::string& message) override {
std::cout << "Email: " << message << std::endl;
}
};
class SMSObserver : public Observer {
public:
void update(const std::string& message) override {
std::cout << "SMS: " << message << std::endl;
}
};
// 使用
Subject subject;
EmailObserver emailObserver;
SMSObserver smsObserver;
subject.attach(&emailObserver);
subject.attach(&smsObserver);
subject.notify("Hello World!");
// 输出:
// Email: Hello World!
// SMS: Hello World!
```
### 编译时多态
**函数重载:**
```cpp
class Printer {
public:
void print(int value) {
std::cout << "Int: " << value << std::endl;
}
void print(double value) {
std::cout << "Double: " << value << std::endl;
}
void print(const std::string& value) {
std::cout << "String: " << value << std::endl;
}
};
// 使用
Printer printer;
printer.print(42); // 调用 print(int)
printer.print(3.14); // 调用 print(double)
printer.print("Hello"); // 调用 print(string)
```
**运算符重载:**
```cpp
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
Complex operator*(const Complex& other) const {
return Complex(real * other.real - imag * other.imag,
real * other.imag + imag * other.real);
}
friend std::ostream& operator<<(std::ostream& os, const Complex& c) {
os << c.real << " + " << c.imag << "i";
return os;
}
};
// 使用
Complex c1(1, 2);
Complex c2(3, 4);
Complex sum = c1 + c2;
Complex product = c1 * c2;
std::cout << sum << std::endl; // 4 + 6i
std::cout << product << std::endl; // -5 + 10i
```
**模板(静态多态):**
```cpp
template <typename T>
T add(T a, T b) {
return a + b;
}
// 使用
int intResult = add(10, 20); // T = int
double doubleResult = add(3.14, 2.71); // T = double
// CRTP(奇异递归模板模式)
template <typename Derived>
class Base {
public:
void interface() {
static_cast<Derived*>(this)->implementation();
}
};
class Derived : public Base<Derived> {
public:
void implementation() {
std::cout << "Derived implementation" << std::endl;
}
};
// 使用
Derived d;
d.interface(); // 输出: Derived implementation
```
### 最佳实践
**1. 始终为多态基类声明虚析构函数**
```cpp
class Base {
public:
virtual ~Base() = default; // 虚析构函数
};
```
**2. 使用 override 关键字确保正确重写**
```cpp
class Derived : public Base {
public:
void func() override { // 明确表示重写
// 实现
}
};
```
**3. 优先使用组合而非继承**
```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; }
};
```
**4. 避免过度使用 dynamic_cast**
```cpp
// 不推荐
if (Dog* dog = dynamic_cast<Dog*>(animal)) {
dog->bark();
} else if (Cat* cat = dynamic_cast<Cat*>(animal)) {
cat->meow();
}
// 推荐:使用虚函数
class Animal {
public:
virtual void makeSound() = 0;
};
class Dog : public Animal {
public:
void makeSound() override { bark(); }
void bark() { std::cout << "Woof!" << std::endl; }
};
```
### 注意事项
- 虚函数调用有性能开销,避免在性能关键路径过度使用
- 构造函数和析构函数中调用虚函数不会发生动态绑定
- 不要在构造函数中调用纯虚函数
- 虚函数不能是静态成员函数
- 避免在基类构造函数中调用虚函数
- 考虑使用 final 关键字阻止不必要的重写
- 谨慎使用 RTTI,它可能影响性能和可维护性服务端2月18日 17:32
C++ 虚函数的实现原理是什么## C++ 虚函数的实现原理
虚函数是 C++ 实现多态性的核心机制,理解其实现原理对于深入掌握 C++ 至关重要。
### 虚函数表(vtable)
虚函数通过虚函数表(Virtual Function Table,简称 vtable)来实现。每个包含虚函数的类都有一个对应的虚函数表。
**vtable 的特点:**
- vtable 是一个静态数组,存储着该类所有虚函数的函数指针
- 每个对象在内存中都有一个指向 vtable 的指针(vptr),通常位于对象内存布局的起始位置
- vtable 在编译时生成,存储在程序的只读数据段
### 内存布局
**包含虚函数的对象内存布局:**
```
+------------------+
| vptr (虚表指针) | 指向该类的 vtable
+------------------+
| 成员变量 1 |
+------------------+
| 成员变量 2 |
+------------------+
| ... |
+------------------+
```
**vtable 的结构:**
```
+------------------+
| type_info 指针 | 用于 RTTI(运行时类型识别)
+------------------+
| 虚函数 1 指针 |
+------------------+
| 虚函数 2 指针 |
+------------------+
| ... |
+------------------+
```
### 虚函数调用过程
当调用虚函数时,编译器会生成类似以下的代码:
```cpp
// 假设调用:obj->virtualFunction()
// 编译器生成的伪代码:
(*(obj->vptr)[index])(obj)
```
**调用步骤:**
1. 通过对象的 vptr 找到对应的 vtable
2. 根据虚函数在 vtable 中的索引找到函数指针
3. 通过函数指针调用实际的函数
### 继承中的 vtable
**单继承:**
- 派生类会继承基类的 vtable
- 派生类重写的虚函数会替换 vtable 中对应的函数指针
- 派生类新增的虚函数会追加到 vtable 的末尾
**多重继承:**
- 派生类会有多个 vtable,每个基类对应一个
- 对象中会有多个 vptr,分别指向不同的 vtable
- 调用虚函数时需要根据基类类型选择正确的 vtable
### 纯虚函数和抽象类
**纯虚函数:**
```cpp
class Shape {
public:
virtual void draw() = 0; // 纯虚函数
virtual double area() = 0;
};
```
**特点:**
- 纯虚函数在 vtable 中对应的函数指针为 nullptr
- 包含纯虚函数的类称为抽象类,不能实例化
- 派生类必须实现所有纯虚函数才能实例化
### 虚析构函数
**为什么需要虚析构函数:**
```cpp
class Base {
public:
virtual ~Base() { // 虚析构函数
cout << "Base destructor" << endl;
}
};
class Derived : public Base {
public:
~Derived() {
cout << "Derived destructor" << endl;
}
};
Base* ptr = new Derived();
delete ptr; // 正确调用 Derived 和 Base 的析构函数
```
**如果不声明为虚析构函数:**
- 只会调用基类的析构函数,导致派生类资源泄漏
### 性能考虑
**虚函数调用的开销:**
- 需要通过 vptr 间接访问 vtable
- 需要通过函数指针间接调用函数
- 破坏了内联优化的可能性
**优化建议:**
- 在性能关键的代码中,避免过度使用虚函数
- 考虑使用 final 关键字阻止进一步重写,可能帮助编译器优化
- 使用 CRTP(奇异递归模板模式)实现静态多态
### 代码示例
```cpp
#include <iostream>
using namespace std;
class Animal {
public:
virtual void makeSound() {
cout << "Animal makes a sound" << endl;
}
virtual ~Animal() {
cout << "Animal destructor" << endl;
}
};
class Dog : public Animal {
public:
void makeSound() override {
cout << "Dog barks" << endl;
}
~Dog() override {
cout << "Dog destructor" << endl;
}
};
class Cat : public Animal {
public:
void makeSound() override {
cout << "Cat meows" << endl;
}
~Cat() override {
cout << "Cat destructor" << endl;
}
};
int main() {
Animal* animals[2];
animals[0] = new Dog();
animals[1] = new Cat();
for (int i = 0; i < 2; i++) {
animals[i]->makeSound(); // 动态绑定
}
for (int i = 0; i < 2; i++) {
delete animals[i]; // 正确调用派生类析构函数
}
return 0;
}
```
### 注意事项
- 虚函数不能是静态函数(static)
- 构造函数不能是虚函数
- 析构函数应该是虚函数,除非确定不会被多态使用
- 在构造函数和析构函数中调用虚函数,不会发生动态绑定服务端2月18日 17:32
C++ 智能指针的使用场景和区别有哪些## C++ 智能指针的使用场景和区别
C++11 引入了智能指针,用于自动管理动态分配的内存,避免内存泄漏和悬空指针问题。智能指针是 RAII(资源获取即初始化)模式的典型应用。
### 三种主要智能指针
**1. std::unique_ptr**
- 独占所有权的智能指针
- 同一时刻只能有一个 unique_ptr 指向对象
- 不可复制,只能移动
- 轻量级,几乎没有额外开销
**2. std::shared_ptr**
- 共享所有权的智能指针
- 多个 shared_ptr 可以指向同一个对象
- 使用引用计数管理对象生命周期
- 可以复制和移动
**3. std::weak_ptr**
- 不控制对象生命周期的智能指针
- 必须与 shared_ptr 配合使用
- 用于解决 shared_ptr 的循环引用问题
- 不增加引用计数
### 使用场景
**std::unique_ptr 适用场景:**
- 对象的所有权明确,不需要共享
- 作为函数返回值返回动态分配的对象
- 容器中存储动态分配的对象
- Pimpl(Pointer to Implementation)模式
**std::shared_ptr 适用场景:**
- 多个对象需要共享同一个资源
- 对象的生命周期不确定,需要延迟释放
- 异步编程中传递对象
- 缓存系统中共享资源
**std::weak_ptr 适用场景:**
- 观察者模式中避免循环引用
- 缓存系统中避免强引用导致资源无法释放
- 打破 shared_ptr 的循环引用
### 代码示例
**std::unique_ptr 示例:**
```cpp
#include <memory>
#include <iostream>
class Widget {
public:
Widget() { std::cout << "Widget constructed\n"; }
~Widget() { std::cout << "Widget destroyed\n"; }
void doSomething() { std::cout << "Widget doing something\n"; }
};
// 创建 unique_ptr
std::unique_ptr<Widget> ptr1 = std::make_unique<Widget>();
// 移动语义
std::unique_ptr<Widget> ptr2 = std::move(ptr1);
// ptr1 现在为 nullptr
// 自定义删除器
auto deleter = [](Widget* w) {
std::cout << "Custom deleter\n";
delete w;
};
std::unique_ptr<Widget, decltype(deleter)> ptr3(new Widget(), deleter);
// 作为函数参数
void processWidget(std::unique_ptr<Widget> ptr) {
ptr->doSomething();
}
processWidget(std::move(ptr2));
```
**std::shared_ptr 示例:**
```cpp
#include <memory>
#include <iostream>
class Resource {
public:
Resource() { std::cout << "Resource created\n"; }
~Resource() { std::cout << "Resource destroyed\n"; }
};
// 创建 shared_ptr
std::shared_ptr<Resource> ptr1 = std::make_shared<Resource>();
std::cout << "Use count: " << ptr1.use_count() << "\n"; // 1
// 复制
std::shared_ptr<Resource> ptr2 = ptr1;
std::cout << "Use count: " << ptr1.use_count() << "\n"; // 2
// 移动
std::shared_ptr<Resource> ptr3 = std::move(ptr1);
std::cout << "Use count: " << ptr2.use_count() << "\n"; // 2
std::cout << "ptr1 is " << (ptr1 ? "not null" : "null") << "\n"; // null
// 自定义删除器
auto deleter = [](Resource* r) {
std::cout << "Custom deleter for Resource\n";
delete r;
};
std::shared_ptr<Resource> ptr4(new Resource(), deleter);
```
**std::weak_ptr 示例:**
```cpp
#include <memory>
#include <iostream>
class Node {
public:
std::shared_ptr<Node> next;
std::weak_ptr<Node> prev; // 使用 weak_ptr 避免循环引用
Node() { std::cout << "Node created\n"; }
~Node() { std::cout << "Node destroyed\n"; }
};
void createCycle() {
auto node1 = std::make_shared<Node>();
auto node2 = std::make_shared<Node>();
node1->next = node2;
node2->prev = node1; // weak_ptr 不会增加引用计数
// node1 和 node2 可以正常释放
}
// 使用 weak_ptr 检查对象是否存在
std::weak_ptr<int> weakPtr;
{
auto sharedPtr = std::make_shared<int>(42);
weakPtr = sharedPtr;
if (auto locked = weakPtr.lock()) {
std::cout << "Value: " << *locked << "\n"; // 42
} else {
std::cout << "Object has been destroyed\n";
}
}
// sharedPtr 离开作用域,对象被销毁
if (auto locked = weakPtr.lock()) {
std::cout << "Value: " << *locked << "\n";
} else {
std::cout << "Object has been destroyed\n"; // 执行这里
}
```
### 性能比较
**内存开销:**
- unique_ptr:几乎无额外开销,只包含一个原始指针
- shared_ptr:包含两个指针(控制块 + 对象指针),约 16 字节
- weak_ptr:与 shared_ptr 类似,包含控制块指针
**操作开销:**
- unique_ptr:所有操作都是 O(1),无额外开销
- shared_ptr:复制和销毁需要原子操作修改引用计数
- weak_ptr:lock() 操作需要原子操作
### 循环引用问题
**问题示例:**
```cpp
class A {
public:
std::shared_ptr<B> b_ptr;
};
class B {
public:
std::shared_ptr<A> a_ptr; // 导致循环引用
};
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->b_ptr = b;
b->a_ptr = a;
// a 和 b 的引用计数永远不会变为 0,内存泄漏
```
**解决方案:**
```cpp
class B {
public:
std::weak_ptr<A> a_ptr; // 使用 weak_ptr 打破循环
};
```
### 最佳实践
**1. 优先使用 std::make_unique 和 std::make_shared**
```cpp
// 推荐
auto ptr = std::make_unique<Widget>();
auto ptr = std::make_shared<Resource>();
// 不推荐
auto ptr = std::unique_ptr<Widget>(new Widget());
auto ptr = std::shared_ptr<Resource>(new Resource());
```
**2. 使用 std::move 转移 unique_ptr 所有权**
```cpp
std::unique_ptr<Widget> createWidget() {
return std::make_unique<Widget>();
}
auto ptr = createWidget(); // 移动构造
```
**3. 避免从裸指针创建 shared_ptr**
```cpp
int* raw = new int(42);
std::shared_ptr<int> ptr1(raw);
std::shared_ptr<int> ptr2(raw); // 错误!会导致双重释放
```
**4. 使用 std::enable_shared_from_this**
```cpp
class MyClass : public std::enable_shared_from_this<MyClass> {
public:
std::shared_ptr<MyClass> getShared() {
return shared_from_this();
}
};
auto obj = std::make_shared<MyClass>();
auto shared = obj->getShared();
```
### 注意事项
- 不要混用裸指针和智能指针管理同一个对象
- 在多线程环境中使用 shared_ptr 时要注意线程安全
- weak_ptr::lock() 返回的 shared_ptr 可能为空
- 避免在循环中频繁创建和销毁 shared_ptr
- 考虑使用 std::observer_ptr(C++26)作为非拥有指针的替代方案