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

  1. 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 的构造函数。
      1. 等价于 return std::any(std::in_place_type, std::forward(args)…);
      1. 等价于 return std::any(std::in_place_type, il, std::forward(args)…);
  • 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.


ALL WILL BE CLEAR