1. std::call_once、std::once_flag
- C++ 版本:C++11
- 头文件:
- 原型:
template< class Callable, class... Args >
void call_once( std::once_flag& flag, Callable&& f, Args&&... args ); (C++11 起)
class once_flag; (C++11 起)
- std::call_once 介绍:
- 准确执行一次可调用 (Callable) 对象 f ,即使同时从多个线程调用。
- 若在调用call_once时,flag指示已经调用了f,则call_once立即返回(称这种为对call_once的消极调用)。否则,call_once 以参数 std::forward
(args)… 调用std::forward (f)(如同用 std::invoke)。 - 不同于std::thread构造函数或std::async,call_once 不移动或复制参数,因为不需要转移它们到另一执行线程(称这种为对 call_once 的积极调用)。
- 若该调用抛异常,则传递异常给call_once的调用方,并且不翻转flag ,其他调用将尝试执行(这种对call_once的调用被称为异常)。
- 若该调用正常返回(这种对call_once的调用被称为返回),则翻转 flag ,并保证以同一 flag 对call_once的其他调用为消极。
- std::once_flag 介绍:
- 类 std::once_flag 是 std::call_once 的辅助类。
- std::once_flag 既不可复制亦不可移动。
- once_flag的生命周期必须要比使用它的线程的生命周期要长
- 用法:
- 用于实现懒汉式的单例模式,以百度apollo项目中的代码为例
#define DISALLOW_COPY_AND_ASSIGN(classname) \
classname(const classname &) = delete; \
classname &operator=(const classname &) = delete;
#define DECLARE_SINGLETON(classname) \
public: \
static classname *Instance(bool create_if_needed = true) { \
static classname *instance = nullptr; \
if (!instance && create_if_needed) { \
static std::once_flag flag; \
std::call_once(flag, \
[&] { instance = new (std::nothrow) classname(); }); \
} \
return instance; \
} \
\
static void CleanUp() { \
auto instance = Instance(false); \
if (instance != nullptr) { \
CallShutdown(instance); \
} \
} \
\
private: \
classname(); \
DISALLOW_COPY_AND_ASSIGN(classname)
2. std::nothrow
- std::nothrow
- C++ 版本:C++11
- 头文件:
- 原型:
extern const std::nothrow_t nothrow;
- 介绍:
- std::nothrow 是 std::nothrow_t 类型的常量
- 普通new创建一个对象时,可能会由于各种原因(内存空间不足)导致创建失败,这时将会抛出std::bad_alloc异常,且这时的指针将不为NULL,因此无法使用NULL判断对象是否创建成功。使用
instance = new (std::nothrow) classname();
的方式创建对象,在失败时不会抛出异常,并且返回一个NULL指针,可以用来判断对象是否创建成功
3. std::any、std::any_cast、std::make_any
- C++ 版本:C++17
- 头文件:
- 原型:
class any; (C++17 起)
template<class T>
T any_cast(const any& operand);
template<class T>
T any_cast(any& operand);
template<class T>
T any_cast(any&& operand);
template<class T>
const T* any_cast(const any* operand) noexcept;
template<class T>
T* any_cast(any* operand) noexcept;
- std::any 介绍:
- 类 any 描述用于任何类型的单个值的类型安全容器。
- 类 any 的对象存储任何满足构造函数要求的类型的一个实例或为空,而这被称为 any 类对象的_状态_。存储的实例被称作所含对象。若两个状态均为空,或均为非空且其所含对象等价,则两个状态等价。
- 非成员 any_cast 函数提供对所含对象的类型安全访问。
- 鼓励实现避免小对象的动态分配,但这种优化仅可以应用于 std::is_nothrow_move_constructible 对其返回 true 的类型。
- std::any 用法:
#include <any>
#include <iostream>
int main() {
// any 类型
std::any a = 1;
std::cout << a.type().name() << ": " << std::any_cast<int>(a) << '\n';
a = 3.14;
std::cout << a.type().name() << ": " << std::any_cast<double>(a) << '\n';
a = true;
std::cout << a.type().name() << ": " << std::any_cast<bool>(a) << '\n';
// 有误的转型,抛出std::bad_any_cast异常
try {
a = 1;
std::cout << std::any_cast<float>(a) << '\n';
} catch (const std::bad_any_cast& e) {
std::cout << e.what() << '\n';
}
// 拥有值
a = 1;
if (a.has_value()) {
std::cout << a.type().name() << '\n';
}
// 重置,reset之后 a.type().name()将会是void
a.reset();
if (!a.has_value()) {
std::cout << "no value\n";
}
// 指向所含数据的指针,转换指针时模板参数仍为类型int而非int*
a = 1;
int* i = std::any_cast<int>(&a);
std::cout << *i << "\n";
}
// 输出:
i: 1
d: 3.14
b: true
bad any_cast
i
no value
1
- std::any_cast 介绍:
- 进行对所含有对象的类型安全访问。
- std::any_cast 用法:
#include <string>
#include <iostream>
#include <any>
#include <utility>
int main() {
// 简单示例
auto a = std::any(12);
std::cout << std::any_cast<int>(a) << '\n';
try {
std::cout << std::any_cast<std::string>(a) << '\n';
} catch(const std::bad_any_cast& e) {
std::cout << e.what() << '\n';
}
// 指针示例
if (int* i = std::any_cast<int>(&a)) {
std::cout << "a is int: " << *i << '\n';
} else if (std::string* s = std::any_cast<std::string>(&a)) {
std::cout << "a is std::string: " << *s << '\n';
} else {
std::cout << "a is another type or unset\n";
}
// 进阶示例
a = std::string("hello");
auto& ra = std::any_cast<std::string&>(a); //< 引用
ra[1] = 'o';
std::cout << "a: "
<< std::any_cast<const std::string&>(a) << '\n'; //< const 引用
auto b = std::any_cast<std::string&&>(std::move(a)); //< 右值引用
// 注意: 'b' 是移动构造的 std::string , 'a' 被置于合法但未指定的状态
std::cout << "a: " << *std::any_cast<std::string>(&a) //< 指针
<< "b: " << b << '\n';
}
// 输出:
12
bad any_cast
a is int: 12
a: hollo
a: b: hollo
- std::make_any 介绍:
- 构造含 T 类型对象的 any 对象,传递提供的参数给 T 的构造函数。
-
- 等价于 return std::any(std::in_place_type
, std::forward (args)…);
- 等价于 return std::any(std::in_place_type
-
- 等价于 return std::any(std::in_place_type
, il, std::forward (args)…);
- 等价于 return std::any(std::in_place_type
- std::make_any 用法:
#include <any>
#include <complex>
#include <functional>
#include <iostream>
#include <string>
int main() {
auto a0 = std::make_any<std::string>("Hello, std::any!\n");
auto a1 = std::make_any<std::complex<double>>(0.1, 2.3);
std::cout << std::any_cast<std::string&>(a0);
std::cout << std::any_cast<std::complex<double>&>(a1) << '\n';
using lambda = std::function<void(void)>;
// 把 lambda 放入 std::any。尝试 #1 (失败)。
std::any a2 = [] { std::cout << "Lambda #1.\n"; };
std::cout << "a2.type() = \"" << a2.type().name() << "\"\n";
// any_cast 转型到 <void(void)> 但实际类型不是
// std::function ……,而是 ~ main::{lambda()#1} ,且它对
// 每个 lambda 唯一。所以这会抛出……
try {
std::any_cast<lambda>(a2)();
}
catch (std::bad_any_cast const& ex) {
std::cout << ex.what() << '\n';
}
// 将 lambda 放入 std::any 中。尝试 #2 (成功)
auto a3 = std::make_any<lambda>([] { std::cout << "Lambda #2.\n"; });
std::cout << "a3.type() = \"" << a3.type().name() << "\"\n";
std::any_cast<lambda>(a3)();
}
// 输出:
Hello, std::any!
(0.1,2.3)
a2.type() = "Z4mainEUlvE_"
bad any_cast
a3.type() = "St8functionIFvvEE"
Lambda #2.
Q.E.D.