接前一篇文章:C++常用容器、函数、类集(3)
本文内容参考:
C++中std::enable_shared_from_this<> 的用法-优快云博客
c++ Lambda表达式详解 - Plus301 - 博客园
特此致谢!
11. std::enable_shared_from_this
std::enable_shared_from_this是C++ 中一种常见的模式,用于在类的成员函数中安全地获取当前对象的 std::shared_ptr。这种模式在异步编程中非常有用,尤其是在网络编程中,因为异步操作通常需要确保对象的生命周期能够延续到操作完成。
在C++的智能指针体系中,std::shared_ptr是一个非常重要的工具,它通过引用计数机制帮助我们管理动态分配的对象生命周期,避免内存泄漏。然而,在某些情况下,我们可能需要从一个对象内部获取指向自身的shared_ptr,这时候就需要使用std::enable_shared_from_this这个辅助类。
在 C++ 中,当一个对象被 std::shared_ptr管理时,如果需要在类的成员函数中获取当前对象的 std::shared_ptr,直接使用this指针是不安全的。例如:
class Connection {
public:
void doSomething() {
// 错误:直接使用 this 创建 shared_ptr 会导致多个独立的 shared_ptr 管理同一个对象
auto self = std::shared_ptr<Connection>(this);
}
};
上面的代码会导致未定义行为,因为多个独立的std::shared_ptr可能会尝试管理同一个对象,从而导致重复释放内存。
为了解决这个问题,C++提供了std::enable_shared_from_this,它允许你从类的成员函数中安全地获取当前对象的 std::shared_ptr。
std::enable_shared_from_this是一个模板类,它提供了一个成员函数shared_from_this(),用于返回当前对象的 std::shared_ptr。使用它的前提是对象必须已经被std::shared_ptr管理。例如:
#include <memory>
#include <iostream>
class Connection : public std::enable_shared_from_this<Connection> {
public:
void doSomething() {
// 安全地获取当前对象的 shared_ptr
auto self = shared_from_this();
std::cout << "Use count: " << self.use_count() << std::endl;
}
};
int main() {
auto conn = std::make_shared<Connection>();
conn->doSomething(); // 输出:Use count: 2
return 0;
}
关键点:
- Connection继承自std::enable_shared_from_this,表示Connection类支持从自身获取 std::shared_ptr。
- 在类的成员函数中,调用shared_from_this()可以安全地获取当前对象的std::shared_ptr。
- 对象必须由std::shared_ptr管理。只有在对象已经被std::shared_ptr管理的情况下,才能调用 shared_from_this()。否则会抛出std::bad_weak_ptr异常。
12. Lambda表达式
Lambda表达式是现代C++在C++ 11和更高版本中的一个新的语法糖,在C++ 11、C++ 14、C++ 17和C++ 20中,Lambda表达的内容还在不断更新。Lambda有很多叫法,有Lambda表达式、Lambda函数、匿名函数。Lambda表达式(也称为Lambda函数)是在调用或作为函数参数传递的位置处定义匿名函数对象的便捷方法。通常,lambda用于封装传递给算法或异步方法的几行代码 。
Lambda表达式语法定义
Lambda表达式语法定义如下:
- 捕获列表
在C ++规范中也称为Lambda导入器, 捕获列表总是出现在Lambda函数的开始处。实际上,[]是Lambda引出符。编译器根据该引出符判断接下来的代码是否是Lambda函数,捕获列表能够捕捉上下文中的变量以供Lambda函数使用。
- 参数列表
与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号“()”一起省略。
- 可变规格
mutable修饰符, 默认情况下Lambda函数总是一个const函数,mutable可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空)。
- 异常说明
用于Lamdba表达式内部函数抛出异常。
- 返回类型
追踪返回类型形式声明函数的返回类型。可以在不需要返回值的时候也可以连同符号”->”一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导。
- Lambda函数体
内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。
Lambda表达式示例
ISO C ++标准官网展示了一个简单的Lambda表示式示例:
#include <algorithm>
#include <cmath>
void abssort(float* x, unsigned n) {
std::sort(x, x + n,
// Lambda expression begins
[](float a, float b) {
return (std::abs(a) < std::abs(b));
} // end of lambda expression
);
}
笔者看到这里的时候,不由想到了Python中的Lambda表达式。对比一下:
更多内容请看下回。