C++新特性(服务器项目)

std::function<void(Socket*)> cb = std::bind(&Server::newConnection, this, std::placeholders::_1);
std::bind

std::bind 是一个用于绑定函数、成员函数或可调用对象的工具,它允许你将某些参数预先绑定到一个函数上,从而生成一个新的可调用对象

std::placeholders::_1

占位符的作用正是为绑定的函数预留参数位置,以便在调用时动态传递参数。它允许你在使用 std::bind 时,预先绑定部分参数,同时为其他参数保留位置,这些参数可以在调用时动态提供。

占位符的编号规则

占位符的编号从 _1 开始,表示调用时传递的第一个参数,_2 表示第二个参数,依此类推。这些占位符的顺序和数量决定了绑定函数的参数顺序和数量。

std::function<void(Socket*)> newConnectionCallback;

std::bind 返回的对象是一个可调用对象,但不是普通函数指针。因此,不能直接将 std::bind 的返回值赋给 void(Socket*) 类型的变量。

std::function 是一个通用的函数封装器,它可以存储任何可调用对象,只要其调用签名匹配即可。

std::move()
 std::function<void()> sub_loop = std::bind(&EventLoop::Loop, sub_reactors_[i]);
thread_pool_->Add(std::move(sub_loop));

sub_loop 变成一个右值,以便进行移动语义。

std::move() 不会移动数据,它只是将一个变量的类型从左值变成右值,让它支持移动语义(Move Semantics)。

  • 左值(Lvalue):可以取地址,有名字,生命周期长。
  • 右值(Rvalue):通常是临时对象,没有名字,生命周期短。

示例:

std::string str = "Hello"; std::string new_str = std::move(str);
  • std::move(str) 不会真的移动 str 的内容,但它告诉编译器 str 已经不需要了,可以被移动
  • new_str 可能会接管 str 的数据,而 str 变成空字符串(避免额外的内存分配)。

std::make_shared和std::shared_ptr<T>
  auto task =
      std::make_shared<std::packaged_task<return_type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
  • std::make_shared 避免了手动 new 和 delete,减少内存泄漏的风险。
    std::shared_ptr 自动管理 std::packaged_task 的生命周期,在没有引用时释放资源。
    比 new 和 std::shared_ptr 分开使用更高效,因为它减少了额外的内存分配。
std::shared_ptr<int> ptr1 = std::make_shared<int>(10);
std::shared_ptr<int> ptr2 = ptr1; // 共享所有权

特点:

  • 多个 shared_ptr 可以共享同一个资源
  • 采用引用计数(Reference Counting),当计数变为 0 时自动释放资源。
  • 可以复制copy),不会导致 delete 被多次调用。

适用场景:

  • 需要 多个对象共享同一个资源
  • 适用于 动态分配的对象,如共享缓存、树结构、图结构等
  • 智能指针 特点 使用场景
    std::unique_ptr<T> 独占所有权,不能复制 适用于 独占资源管理,如文件句柄、数据库连接
    std::shared_ptr<T> 引用计数,可多个 shared_ptr 共享 适用于 多个对象共享同一资源,如缓存、图结构
    std::make_shared<T>() 高效创建 shared_ptr(单次内存分配) 推荐使用,避免 new
std::unique_ptr<T> 

C++11 之前:

  • 需要手动管理 动态分配的对象newdelete),容易导致内存泄漏。

C++11 引入的改进:

  • std::unique_ptr<T>独占所有权 的智能指针,保证资源不会被泄露。
  • unique_ptr 作用域结束时,自动释放资源

特点:

  • 只有一个指针拥有资源,不能被复制(copy)。
    但可以通过 std::move() 转移所有权。
    当 unique_ptr 离开作用域时,自动释放资源(调用 delete)。

适用场景:

  • 需要唯一所有权,不需要多个对象共享同一个资源。
  • 适用于 RAII(资源获取即初始化) 管理,如文件句柄、数据库连接等

用法:

std::unique_ptr<Socket> socket_; std::unique_ptr<Channel> channel_;

优势:

🚀 std::unique_ptr<T> 适合独占资源,std::shared_ptr<T> 适合多线程共享!

  • 避免 newdelete 造成的 内存泄漏
  • 不能被复制,只能通过 std::move() 转移所有权,防止 意外的多重释放
  • std::unique_ptr<T> 不能在多个线程共享,但可以用 std::move() 转移所有权。
  • std::unique_ptr<T> 不是线程安全的,如果多个线程访问它,需要用 std::mutex 保护。
  • std::shared_ptr<T> 支持多线程共享,内部采用原子操作管理引用计数,适用于多线程环境。
  • 优先使用 std::unique_ptr<T>,只有当确实需要多个线程共享资源时,才使用 std::shared_ptr<T>
问题 std::unique_ptr<T> std::shared_ptr<T>
能否多个线程共享? 不能,每次只能一个线程拥有 可以,多个线程共享
能否在多个线程间转移? 可以,但必须用 std::move() ✅ 共享资源,自动管理引用计数
线程安全? 不是,需要 std::mutex 保护 线程安全(内部有原子操作)
适用场景 资源必须唯一所有权,适用于文件句柄、数据库连接等 多线程共享资源,适用于缓存、任务队列等

std::make_unique<T>()

std::make_unique<T>() 是一个工厂函数,用于创建 unique_ptr,它比直接使用 new 创建对象并传递给 unique_ptr 更安全和简洁。它在 C++14 中被引入,主要解决了几个问题:

  • 避免裸指针泄漏:使用 std::make_unique 可以避免裸指针泄漏问题。因为它确保了创建对象和包装在 unique_ptr 之间的一致性,避免了在对象创建失败时忘记释放内存的情况。
  • 避免重复的 new 操作std::make_unique 自动将 new 操作封装在内部,不需要显式调用 new,从而减少代码冗余。

创建 std::unique_ptr<T>

std::unique_ptr<Socket> socket_ = std::make_unique<Socket>();
  • 通过 std::make_unique 创建 Socket 对象,并返回一个指向该对象的 unique_ptr
  • std::make_unique 无法传递 nullptr,它总是返回有效的指针。
  • 特性 std::unique
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值