4140 字
21 分钟
C++11 部分特性探讨

C++高级编程技术详解#

1. 智能指针:shared_ptr#

基本概念与用法#

shared_ptr 是 C++11 引入的智能指针,采用引用计数机制自动管理动态分配的内存,有效防止内存泄漏和悬空指针问题。

#include <memory>
#include <iostream>
int main() {
// 创建 shared_ptr 的几种方式
std::shared_ptr<int> ptr1(new int(42)); // 直接初始化
std::shared_ptr<int> ptr2 = std::make_shared<int>(42); // 推荐方式,更高效
auto ptr3 = std::make_shared<int>(42); // 使用 auto 关键字
// 访问指针内容
std::cout << "Value: " << *ptr1 << std::endl; // 解引用
std::cout << "Address: " << ptr1.get() << std::endl; // 获取裸指针
// 检查是否唯一所有者
std::cout << "Use count: " << ptr1.use_count() << std::endl;
std::cout << "Unique: " << ptr1.unique() << std::endl;
return 0;
}

引用计数机制详解#

每个 shared_ptr 都会记录有多少个指针指向同一块内存,这个引用计数会随着指向该内存的 shared_ptr 数量的变化而动态调整:

#include <memory>
#include <iostream>
void demonstrate_reference_counting() {
auto ptr1 = std::make_shared<int>(100);
std::cout << "After ptr1 creation - use_count: " << ptr1.use_count() << std::endl; // 1
{
auto ptr2 = ptr1; // 拷贝构造,引用计数+1
std::cout << "After ptr2 creation - use_count: " << ptr1.use_count() << std::endl; // 2
auto ptr3 = ptr1; // 引用计数再+1
std::cout << "After ptr3 creation - use_count: " << ptr1.use_count() << std::endl; // 3
} // ptr2 和 ptr3 离开作用域被销毁,引用计数-2
std::cout << "After ptr2, ptr3 destroyed - use_count: " << ptr1.use_count() << std::endl; // 1
ptr1.reset(); // 手动释放,引用计数归零,内存被释放
std::cout << "After reset - use_count: " << ptr1.use_count() << std::endl; // 0
}

自定义删除器#

shared_ptr 支持自定义删除器,这在管理特殊资源时非常有用:

#include <memory>
#include <iostream>
// 自定义删除器示例
struct FileDeleter {
void operator()(FILE* file) {
if (file) {
fclose(file);
std::cout << "File closed successfully" << std::endl;
}
}
};
void custom_deleter_example() {
// 使用自定义删除器管理文件资源
std::shared_ptr<FILE> file_ptr(fopen("test.txt", "w"), FileDeleter());
if (file_ptr) {
fputs("Hello, World!", file_ptr.get());
}
// 文件会在 shared_ptr 销毁时自动关闭
}
// Lambda 表达式作为删除器
void lambda_deleter_example() {
auto array_deleter = [](int* arr) {
delete[] arr;
std::cout << "Array deleted" << std::endl;
};
std::shared_ptr<int> arr_ptr(new int[10], array_deleter);
}

循环引用问题及解决方案#

shared_ptr 可能导致循环引用,需要使用 weak_ptr 来打破:

#include <memory>
#include <iostream>
struct Node {
std::string name;
std::shared_ptr<Node> next;
std::weak_ptr<Node> prev; // 使用 weak_ptr 避免循环引用
Node(const std::string& n) : name(n) {
std::cout << "Node " << name << " created" << std::endl;
}
~Node() {
std::cout << "Node " << name << " destroyed" << std::endl;
}
};
void circular_reference_example() {
auto node1 = std::make_shared<Node>("A");
auto node2 = std::make_shared<Node>("B");
node1->next = node2;
node2->prev = node1; // 使用 weak_ptr,不会增加引用计数
std::cout << "node1 use_count: " << node1.use_count() << std::endl; // 1
std::cout << "node2 use_count: " << node2.use_count() << std::endl; // 2
}

2. 网络 I/O 编程#

TCP 服务器完整实现#

// Tcp Server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <errno.h>
#define PORT 8080 // 服务器端口号(非特权端口,1024-65535)
#define BACKLOG 10 // 最大等待连接队列长度
#define BUFFER_SIZE 1024 // 数据缓冲区大小
#define MAX_CLIENTS 100 // 最大客户端数量
// 全局变量,用于信号处理
static volatile int keep_running = 1;
// 信号处理函数
void signal_handler(int sig) {
keep_running = 0;
printf("\nReceived signal %d, shutting down...\n", sig);
}
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE] = {0};
// 设置信号处理
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
// 1. 创建 TCP 套接字
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 设置 SO_REUSEADDR 选项,避免 TIME_WAIT 状态导致绑定失败
int opt = 1;
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
perror("setsockopt failed");
close(server_fd);
exit(EXIT_FAILURE);
}
// 2. 设置服务器地址结构
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 3. 绑定套接字
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
close(server_fd);
exit(EXIT_FAILURE);
}
// 4. 开始监听
if (listen(server_fd, BACKLOG) < 0) {
perror("listen failed");
close(server_fd);
exit(EXIT_FAILURE);
}
printf("TCP Server started successfully, listening on port: %d\n", PORT);
printf("Press Ctrl+C to stop the server\n");
// 5. 主服务器循环
while (keep_running) {
// 使用 select 实现非阻塞检查,避免永久阻塞在 accept
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(server_fd, &read_fds);
struct timeval timeout;
timeout.tv_sec = 1; // 1秒超时
timeout.tv_usec = 0;
int activity = select(server_fd + 1, &read_fds, NULL, NULL, &timeout);
if (activity < 0 && errno != EINTR) {
perror("select error");
break;
}
if (!keep_running) {
break; // 收到停止信号
}
if (activity > 0 && FD_ISSET(server_fd, &read_fds)) {
// 接受新连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t*)&addrlen)) < 0) {
perror("accept failed");
continue;
}
// 打印客户端信息
printf("New client connected: %s:%d\n",
inet_ntoa(address.sin_addr),
ntohs(address.sin_port));
// 处理客户端请求
handle_client(new_socket, &address);
}
}
// 清理资源
printf("Server shutdown complete\n");
close(server_fd);
return 0;
}
// 客户端处理函数
void handle_client(int client_socket, struct sockaddr_in* client_addr) {
char buffer[BUFFER_SIZE];
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(client_addr->sin_addr), client_ip, INET_ADDRSTRLEN);
int client_port = ntohs(client_addr->sin_port);
while (1) {
memset(buffer, 0, BUFFER_SIZE);
ssize_t bytes_read = read(client_socket, buffer, BUFFER_SIZE - 1);
if (bytes_read < 0) {
perror("read failed");
break;
} else if (bytes_read == 0) {
printf("Client %s:%d disconnected\n", client_ip, client_port);
break;
}
// 处理接收到的数据
buffer[bytes_read] = '\0';
printf("Received from %s:%d: %s\n", client_ip, client_port, buffer);
// 简单的回声服务器逻辑
std::string response = "Echo: " + std::string(buffer);
if (send(client_socket, response.c_str(), response.length(), 0) < 0) {
perror("send failed");
break;
}
// 检查退出命令
if (strncmp(buffer, "quit", 4) == 0) {
printf("Client %s:%d requested disconnect\n", client_ip, client_port);
break;
}
}
close(client_socket);
}

TCP 客户端实现#

// TCP Client implementation
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>
#include <string>
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8080
#define BUFFER_SIZE 1024
class TCPClient {
private:
int sockfd;
struct sockaddr_in server_addr;
public:
TCPClient() : sockfd(-1) {
memset(&server_addr, 0, sizeof(server_addr));
}
bool connectToServer(const std::string& ip, int port) {
// 创建套接字
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket creation failed");
return false;
}
// 设置服务器地址
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
if (inet_pton(AF_INET, ip.c_str(), &server_addr.sin_addr) <= 0) {
perror("Invalid address");
close(sockfd);
return false;
}
// 连接服务器
if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("Connection failed");
close(sockfd);
return false;
}
std::cout << "Connected to server " << ip << ":" << port << std::endl;
return true;
}
void sendMessage(const std::string& message) {
if (send(sockfd, message.c_str(), message.length(), 0) < 0) {
perror("Send failed");
return;
}
std::cout << "Sent: " << message << std::endl;
// 接收响应
char buffer[BUFFER_SIZE] = {0};
ssize_t bytes_received = read(sockfd, buffer, BUFFER_SIZE - 1);
if (bytes_received > 0) {
buffer[bytes_received] = '\0';
std::cout << "Received: " << buffer << std::endl;
}
}
void disconnect() {
if (sockfd >= 0) {
close(sockfd);
sockfd = -1;
std::cout << "Disconnected from server" << std::endl;
}
}
~TCPClient() {
disconnect();
}
};
// 使用示例
int main() {
TCPClient client;
if (client.connectToServer(SERVER_IP, SERVER_PORT)) {
client.sendMessage("Hello, Server!");
client.sendMessage("How are you?");
client.sendMessage("quit"); // 退出命令
}
return 0;
}

程序执行流程深度解析#

完整的程序启动和执行流程:

编译 → 链接 → 加载 → 运行时初始化 → main → 清理退出

详细步骤:

  1. 编译阶段:源代码编译为目标文件
  2. 链接阶段:链接器将目标文件与库文件合并生成可执行文件
  3. 加载阶段:操作系统加载可执行文件到内存,创建进程
  4. 运行时初始化
    • 执行 _start 入口点(由 CRT 提供)
    • 调用 __libc_start_main 初始化 C 运行时环境
    • 设置堆栈、初始化全局变量、解析命令行参数
  5. main 函数执行:执行用户编写的代码
  6. 清理退出
    • 调用全局对象析构函数
    • 执行 atexit 注册的函数
    • 调用 _exit 系统调用终止进程

网络地址类型详解#

类型本质访问范围典型场景使用示例
eth0: 192.168.243.123具体接口的 IP仅限通过 eth0 接口的外部 / 内部访问局域网内服务通信bind(server_fd, &addr, len)
lo: 127.0.0.1回环接口的本地 IP仅限本机内部访问本地服务测试、进程间通信本地测试、IPC
any: 0.0.0.0通配符地址(所有接口)所有接口的外部 / 内部访问服务器监听所有网络(默认配置)INADDR_ANY

TCP 连接状态问题深度分析#

TIME_WAIT 状态详解#

产生原因: TIME_WAIT 是 TCP 四次挥手过程中的正常状态,确保网络中延迟的数据包能够被正确处理。

大量 TIME_WAIT 的解决方案

// 1. 设置 SO_REUSEADDR 选项
int reuse = 1;
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
perror("setsockopt SO_REUSEADDR failed");
}
// 2. 使用连接池管理连接
class ConnectionPool {
private:
std::queue<int> available_connections;
std::unordered_set<int> all_connections;
size_t max_pool_size;
public:
ConnectionPool(size_t max_size) : max_pool_size(max_size) {}
int getConnection() {
if (!available_connections.empty()) {
int conn = available_connections.front();
available_connections.pop();
return conn;
}
if (all_connections.size() < max_pool_size) {
int new_conn = createNewConnection();
all_connections.insert(new_conn);
return new_conn;
}
return -1; // 连接池已满
}
void returnConnection(int conn) {
available_connections.push(conn);
}
};
// 3. 调整系统参数(需要 root 权限)
// 编辑 /etc/sysctl.conf:
// net.ipv4.tcp_tw_reuse = 1
// net.ipv4.tcp_tw_recycle = 1 # 注意:这个选项在现代内核中已被移除
// net.ipv4.tcp_fin_timeout = 30 # 减少 FIN_WAIT2 超时时间

CLOSE_WAIT 状态问题排查#

根本原因:应用程序没有正确关闭连接。

排查和解决方法

// 1. 确保所有路径都正确关闭连接
void handle_client_robust(int client_socket) {
// 使用 RAII 确保资源释放
class SocketGuard {
private:
int& sockfd;
public:
SocketGuard(int& sock) : sockfd(sock) {}
~SocketGuard() {
if (sockfd >= 0) {
close(sockfd);
sockfd = -1;
}
}
} guard(client_socket);
// 业务逻辑处理
process_client_request(client_socket);
// guard 析构时会自动关闭 socket
}
// 2. 添加超时机制
#include <sys/select.h>
bool receive_with_timeout(int sockfd, char* buffer, size_t size, int timeout_sec) {
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(sockfd, &read_fds);
struct timeval timeout;
timeout.tv_sec = timeout_sec;
timeout.tv_usec = 0;
int result = select(sockfd + 1, &read_fds, NULL, NULL, &timeout);
if (result > 0 && FD_ISSET(sockfd, &read_fds)) {
return read(sockfd, buffer, size) > 0;
}
return false;
}
// 3. 使用状态机管理连接生命周期
enum class ConnectionState {
CONNECTED,
READING,
WRITING,
CLOSING,
CLOSED
};
class Connection {
private:
int sockfd;
ConnectionState state;
time_t last_activity;
public:
void check_timeout() {
time_t now = time(nullptr);
if (now - last_activity > 30) { // 30秒超时
close_connection();
}
}
void close_connection() {
if (state != ConnectionState::CLOSED) {
shutdown(sockfd, SHUT_RDWR);
close(sockfd);
state = ConnectionState::CLOSED;
}
}
};

3. C++20 协程#

协程基础概念#

协程 vs 普通函数

特性普通函数协程
执行流程一次性执行完成可暂停和恢复
状态保存不保存局部变量状态保存完整的执行状态
调用关系调用者等待被调用者完成调用者和被调用者可交替执行
适用场景简单同步逻辑异步I/O、生成器、状态机

完整的协程框架实现#

#include <coroutine>
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <vector>
// 1. 简单的任务协程
struct SimpleTask {
struct promise_type {
SimpleTask get_return_object() {
return SimpleTask{
std::coroutine_handle<promise_type>::from_promise(*this)
};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() { std::terminate(); }
};
std::coroutine_handle<promise_type> handle;
explicit SimpleTask(std::coroutine_handle<promise_type> h) : handle(h) {}
~SimpleTask() {
if (handle) handle.destroy();
}
void resume() {
if (handle && !handle.done()) handle.resume();
}
bool done() const {
return handle.done();
}
};
// 2. 带值的任务协程
template<typename T>
struct ValueTask {
struct promise_type {
T value;
ValueTask get_return_object() {
return ValueTask{
std::coroutine_handle<promise_type>::from_promise(*this)
};
}
std::suspend_never initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_value(T val) { value = std::move(val); }
void unhandled_exception() { std::terminate(); }
// 支持 co_yield
std::suspend_always yield_value(T val) {
value = std::move(val);
return {};
}
};
std::coroutine_handle<promise_type> handle;
explicit ValueTask(std::coroutine_handle<promise_type> h) : handle(h) {}
~ValueTask() { if (handle) handle.destroy(); }
T get_value() const { return handle.promise().value; }
void resume() { if (!handle.done()) handle.resume(); }
bool done() const { return handle.done(); }
};
// 3. 异步操作等待器
struct AsyncOperation {
bool completed{false};
std::function<void()> completion_handler;
bool await_ready() const {
return completed;
}
void await_suspend(std::coroutine_handle<> handle) {
// 模拟异步操作
std::thread([this, handle]() mutable {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
completed = true;
if (completion_handler) completion_handler();
handle.resume(); // 恢复协程
}).detach();
}
void await_resume() {
std::cout << "Async operation completed!" << std::endl;
}
};
// 4. 高级生成器实现
template<typename T>
class Generator {
public:
struct promise_type {
T current_value;
std::exception_ptr exception;
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 = std::move(value);
return {};
}
void return_void() {}
void unhandled_exception() {
exception = std::current_exception();
}
};
using handle_type = std::coroutine_handle<promise_type>;
explicit Generator(handle_type h) : coro(h) {}
~Generator() {
if (coro) coro.destroy();
}
// 禁用拷贝
Generator(const Generator&) = delete;
Generator& operator=(const Generator&) = delete;
// 允许移动
Generator(Generator&& other) noexcept : coro(other.coro) {
other.coro = {};
}
Generator& operator=(Generator&& other) noexcept {
if (this != &other) {
if (coro) coro.destroy();
coro = other.coro;
other.coro = {};
}
return *this;
}
// 迭代器支持
class iterator {
public:
explicit iterator(handle_type coro = {}) : coro(coro) {}
iterator& operator++() {
if (coro && !coro.done()) {
coro.resume();
}
return *this;
}
bool operator==(const iterator& other) const {
return coro == other.coro || (coro.done() && other.coro.done());
}
bool operator!=(const iterator& other) const {
return !(*this == other);
}
const T& operator*() const {
return coro.promise().current_value;
}
const T* operator->() const {
return &coro.promise().current_value;
}
private:
handle_type coro;
};
iterator begin() {
if (coro && !coro.done()) {
coro.resume();
}
return iterator{coro};
}
iterator end() {
return iterator{};
}
private:
handle_type coro;
};

协程使用示例#

// 1. 生成器使用示例
Generator<int> fibonacci(int limit) {
int a = 0, b = 1;
for (int i = 0; i < limit; ++i) {
co_yield a;
std::tie(a, b) = std::make_pair(b, a + b);
}
}
Generator<std::string> tokenize(const std::string& text, char delimiter) {
size_t start = 0, end = 0;
while ((end = text.find(delimiter, start)) != std::string::npos) {
co_yield text.substr(start, end - start);
start = end + 1;
}
co_yield text.substr(start);
}
// 2. 异步任务使用示例
ValueTask<int> async_multiply(int a, int b) {
std::cout << "Starting async multiplication..." << std::endl;
// 模拟异步操作
co_await AsyncOperation{};
int result = a * b;
std::cout << "Multiplication completed: " << a << " * " << b << " = " << result << std::endl;
co_return result;
}
SimpleTask run_async_operations() {
std::cout << "Starting multiple async operations..." << std::endl;
auto task1 = async_multiply(6, 7);
auto task2 = async_multiply(8, 9);
// 等待任务完成
while (!task1.done() || !task2.done()) {
if (!task1.done()) task1.resume();
if (!task2.done()) task2.resume();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
std::cout << "All operations completed!" << std::endl;
std::cout << "Results: " << task1.get_value() << ", " << task2.get_value() << std::endl;
}
// 3. 网络I/O协程示例(概念性)
struct AsyncReadOperation {
int socket_fd;
char* buffer;
size_t size;
bool await_ready() { return false; }
void await_suspend(std::coroutine_handle<> handle) {
// 在实际实现中,这里会使用 epoll/kqueue/IOCP 等异步I/O机制
std::thread([this, handle]() mutable {
ssize_t bytes_read = read(socket_fd, buffer, size);
if (bytes_read >= 0) {
handle.resume();
}
// 错误处理...
}).detach();
}
ssize_t await_resume() {
// 返回实际读取的字节数
return 0; // 简化实现
}
};
// 主函数演示
int main() {
std::cout << "=== Generator Examples ===" << std::endl;
// 斐波那契数列生成器
std::cout << "Fibonacci sequence: ";
for (auto num : fibonacci(10)) {
std::cout << num << " ";
}
std::cout << std::endl;
// 字符串分割生成器
std::cout << "Tokenized string: ";
for (const auto& token : tokenize("hello,world,how,are,you", ',')) {
std::cout << "[" << token << "] ";
}
std::cout << std::endl;
std::cout << "\n=== Async Task Examples ===" << std::endl;
run_async_operations();
return 0;
}

协程性能优化技巧#

// 1. 协程内存池
class CoroutineMemoryPool {
private:
std::vector<std::unique_ptr<char[]>> memory_blocks;
size_t block_size;
public:
CoroutineMemoryPool(size_t size = 4096) : block_size(size) {}
void* allocate(size_t size) {
if (size <= block_size && !memory_blocks.empty()) {
auto block = std::move(memory_blocks.back());
memory_blocks.pop_back();
return block.release();
}
return ::operator new(size);
}
void deallocate(void* ptr, size_t size) {
if (size <= block_size) {
memory_blocks.push_back(std::unique_ptr<char[]>(static_cast<char*>(ptr)));
} else {
::operator delete(ptr);
}
}
};
// 2. 自定义协程内存分配器
template<typename Promise>
struct custom_coroutine_traits {
static CoroutineMemoryPool pool;
static void* operator new(size_t size) {
return pool.allocate(size);
}
static void operator delete(void* ptr, size_t size) {
pool.deallocate(ptr, size);
}
};
// 3. 批量协程调度
class CoroutineScheduler {
private:
std::vector<std::coroutine_handle<>> ready_coroutines;
std::vector<std::coroutine_handle<>> suspended_coroutines;
public:
void schedule(std::coroutine_handle<> coro) {
ready_coroutines.push_back(coro);
}
void run_batch(size_t max_executions = 1000) {
for (size_t i = 0; i < max_executions && !ready_coroutines.empty(); ++i) {
auto coro = ready_coroutines.back();
ready_coroutines.pop_back();
if (!coro.done()) {
coro.resume();
if (!coro.done()) {
suspended_coroutines.push_back(coro);
}
}
}
// 交换准备就绪的协程
std::swap(ready_coroutines, suspended_coroutines);
suspended_coroutines.clear();
}
};

协程最佳实践和陷阱#

最佳实践

  1. 使用 RAII 管理协程句柄
  2. 避免在协程中持有大量堆栈数据
  3. 使用生成器处理大数据序列
  4. 合理设置协程调度策略

常见陷阱

// 错误示例:悬空引用
Generator<int&> bad_generator() {
int value = 42;
co_yield value; // 错误:返回局部变量的引用
} // value 被销毁,引用悬空
// 正确做法:返回值或使用智能指针
Generator<std::unique_ptr<int>> good_generator() {
auto value = std::make_unique<int>(42);
co_yield std::move(value);
}
// 错误示例:忘记检查协程状态
void unsafe_coroutine_use() {
auto coro = some_coroutine();
coro.resume();
// 可能访问已销毁的协程
}
// 正确做法:使用 RAII 和状态检查
class SafeCoroutineWrapper {
std::coroutine_handle<> handle;
bool valid{false};
public:
template<typename Coroutine>
SafeCoroutineWrapper(Coroutine&& coro) : handle(coro.handle), valid(true) {}
~SafeCoroutineWrapper() {
if (valid && handle) {
handle.destroy();
}
}
bool resume() {
if (valid && handle && !handle.done()) {
handle.resume();
return true;
}
return false;
}
// 禁用拷贝,允许移动
SafeCoroutineWrapper(const SafeCoroutineWrapper&) = delete;
SafeCoroutineWrapper& operator=(const SafeCoroutineWrapper&) = delete;
SafeCoroutineWrapper(SafeCoroutineWrapper&& other) noexcept
: handle(other.handle), valid(other.valid) {
other.valid = false;
}
};

4. 综合应用:基于协程的网络服务器#

#include <coroutine>
#include <iostream>
#include <memory>
#include <vector>
#include <unordered_map>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
// 基于协程的异步TCP服务器
class AsyncTCPServer {
private:
int server_fd;
std::unordered_map<int, std::coroutine_handle<>> client_coroutines;
public:
AsyncTCPServer(int port) {
server_fd = socket(AF_INET, SOCK_STREAM, 0);
// 设置非阻塞
fcntl(server_fd, F_SETFL, O_NONBLOCK);
sockaddr_in server_addr{};
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
bind(server_fd, (sockaddr*)&server_addr, sizeof(server_addr));
listen(server_fd, 10);
}
~AsyncTCPServer() {
for (auto& [fd, coro] : client_coroutines) {
if (coro) coro.destroy();
close(fd);
}
close(server_fd);
}
// 接受连接的协程
struct AcceptOperation {
AsyncTCPServer& server;
int client_fd{-1};
bool await_ready() { return false; }
void await_suspend(std::coroutine_handle<> handle) {
// 在实际实现中,这里会注册到epoll等事件循环
std::thread([this, handle]() mutable {
sockaddr_in client_addr{};
socklen_t addr_len = sizeof(client_addr);
while ((client_fd = accept(server.server_fd,
(sockaddr*)&client_addr,
&addr_len)) < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (client_fd >= 0) {
fcntl(client_fd, F_SETFL, O_NONBLOCK);
handle.resume();
}
}).detach();
}
int await_resume() { return client_fd; }
};
AcceptOperation async_accept() {
return AcceptOperation{*this};
}
// 处理客户端连接的协程任务
SimpleTask handle_client(int client_fd) {
char buffer[1024];
while (true) {
// 模拟异步读取
co_await AsyncOperation{};
ssize_t bytes_read = read(client_fd, buffer, sizeof(buffer) - 1);
if (bytes_read <= 0) {
break;
}
buffer[bytes_read] = '\0';
std::cout << "Received: " << buffer << std::endl;
// 回声响应
write(client_fd, buffer, bytes_read);
}
close(client_fd);
client_coroutines.erase(client_fd);
}
// 启动服务器
SimpleTask start() {
std::cout << "Async TCP Server started" << std::endl;
while (true) {
int client_fd = co_await async_accept();
if (client_fd >= 0) {
std::cout << "New client connected: " << client_fd << std::endl;
auto task = handle_client(client_fd);
client_coroutines[client_fd] = task.handle;
}
}
}
};
// 使用示例
int main() {
AsyncTCPServer server(8080);
// 在实际应用中,这里会有事件循环来驱动协程
auto main_task = server.start();
// 简单的事件循环模拟
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return 0;
}

这个完整的指南涵盖了现代 C++ 编程中的三个重要主题:智能指针、网络编程和协程。每个主题都包含了从基础到高级的详细说明、实际代码示例和最佳实践建议,可以帮助开发者深入理解这些概念并在实际项目中应用它们。

C++11 部分特性探讨
https://mizuki.mysqil.com/posts/20251027_1/20251027/
作者
泠时月
发布于
2025-10-27
许可协议
CC BY 4.0

部分信息可能已经过时

封面
示例歌曲
示例艺术家
封面
示例歌曲
示例艺术家
0:00 / 0:00