C11

C11标准

{} 初始化(列表初始化

 

  • 所有容器均支持{}的初始化,并且可以不写=。但要注意保持代码可读性
  • 对于自定义类型,还会调用构造函数
  • 相较于构造函数的单参数隐式类型转换,{}支持多参数的隐式类型转换。
  • 并且创建的临时对象同样具有常性
1
2
3
4
5
6
---
int* ptr1 = new int[3]{1,2,3};

My_class* ptr2 = new My_class[2]{e1,e2};

---

initializer_list:

  • 对于常量数组,创建了一个新的类型std::initializer_list

  • 这样就导致了如下的语句在C++11中不能使用。

  • const int* ptr1 = {1,2,3};,因为花括号内会被识别为std::initializer_list

auto::

  • 其用于定义变量时,自动识别类型。要求必须进行显示初始化,例如:auto pf = malloc创建一个指向malloc的函数指针。
  • typeid(var).name()可以查看var的类型,返回值是一个字符串。

decltype::

  • 也可以自动识别对象,表达式的类型,可以用于定义变量或者作为模板实参。 例如:
    • decltype<var> new_var
    • F_Name<decltype(var)> new_var

nullptr::

  • 由于C++中NULL被定义成字面量0,这样就可能回带来一些问题,因为0既能指针常量,又能表示整形常量。所以出于清晰和安全的角度考虑,C++11中新增了nullptr,用于表示空指针。

新增容器:

  • unordered_map

  • unordered_set

  • template<class T,std::size_t N> struct array;静态数组。

  • template<classT,classAllocator = std::allocator<T>> classforward_list;
    单链表。

cbein,cend

所有容器均支持emplace

  • emplace系列函数提供了一种在容器中直接构造元素的方法。这与insert或push_back等方法不同,后者通常需要先构造对象然后再将其复制或移动到容器中,而emplace则是在容器的内部直接构造对象,从而避免了不必要的拷贝或移动操作。
1
template <class... Args>iterator emplace (const_iterator position, Args&&... args);

包装器

  • std::function:一个通用的函数包装器,可以封装任何可调用对象(例如函数指针、Lambda 表达式、函数对象等)。function本质是一个类模板。
    1
    2
    3
    4
    5
    6
    7
    8
    std::function在头文件<functional>
    // 类模板原型如下
    template <class T> function;     // undefined
    template <class Ret, class... Args>
    class function<Ret(Args...)>;
    模板参数说明:
    Ret: 被调用函数的返回类型
    Args…:被调用函数的形参
    • function的简单使用

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      #include <functional>
      #include <iostream>

      void print(int x) {
      std::cout << x << std::endl;
      }

      int main() {
      std::function<void(int)> func = print;
      func(42); // 调用封装的函数
      return 0;
      }

    -std::bind:用于绑定函数对象的某些参数,使得可以创建新的函数对象,其中一些参数已经被指定了具体的值。

1
2
3
4
5
6
7
8
9
10
11
12
#include <functional>
#include <iostream>

void print(int x, int y) {
std::cout << x << ", " << y << std::endl;
}

int main() {
auto bound_func = std::bind(print,std::placeholders::_2,std::placeholders::_1);
bound_func(10,20); // 输出: 20, 10
return 0;
}

std::function:用于存储和调用可调用对象的通用包装器。

  • 并且包装器可以和using一起使用,用于起别名,using也可以用来给模板起别名。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <functional>

// 使用 using 关键字为函数类型创建别名
using Callback = std::function<void(int)>;

void registerCallback(Callback cb) {
cb(10); // 调用传递进来的回调函数
}

void myCallbackFunction(int value) {
std::cout << "Callback called with value: " << value << std::endl;
}

int main() {
// 注册回调函数
registerCallback(myCallbackFunction);

// 也可以使用 lambda 表达式
registerCallback([](int value) {
std::cout << "Lambda callback with value: " << value << std::endl;
});

return 0;
}

函数模板——std::bind

std::bind 的基本用法

std::bind 的语法如下:

1
std::bind(function, arg1, arg2, ..., std::placeholders::_1, std::placeholders::_2, ...)
  • function:要绑定的函数,可以是函数指针、成员函数指针、全局函数或静态成员函数。

  • arg1, arg2, ...:要绑定到函数的参数。这些参数可以是值、引用或指针。

  • std::placeholders::_1, std::placeholders::_2, ...:占位符,表示当调用生成的可调用对象时,这些位置将被传递给可调用对象的实际参数所替代。

    • 如果传递的是一个对象函数,那么还需要加上实例化对象的(this)指针。
1
2
3
/*例如*/

_client.setConnectionCallback(std::bind(&DictClient::onConnection, this, std::placeholders::_1));
  • std::bind 通过绑定特定参数和使用占位符,提供了一种自动适配函数参数的能力。(上述例子中就是)
  • 绑定的底层是生成了一个仿函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
/*使用样例*/
#include <iostream>
#include <functional>

void print(int a, int b) {
std::cout << a << " " << b << std::endl;
}

int main() {
auto bind_func = std::bind(print, std::placeholders::_1, 20);
bind_func(10); // 输出: 10 20
return 0;
}

原子操作

  • atomic会创建一个原子对象。
    1
    2
    3
    static std::atomic<size_t> seq(1); 
    size_t cur = seq.fetch_add(1);

mutex

  • **std::mutex**:
    • std::mutex 是 C++11 引入的一个同步原语,用于保护共享数据,防止多个线程同时访问,从而避免数据竞争和不一致性。
  1. **std::unique_lock**:
  • std::unique_lock 是一个灵活的锁管理器,它对 std::mutex(或其他可锁对象,如 std::timed_mutexstd::recursive_mutex 等)进行独占所有权管理。
  • std::unique_lock 的主要特点是:它确保了在其生命周期结束时,互斥量会被自动释放(解锁),从而防止由于忘记手动解锁而导致的死锁或其他问题。
  • std::unique_lock 还提供了比 std::lock_guard 更高级的功能,如延迟锁定、提前解锁、尝试锁定和超时锁定等。
  1. **std::unique_lock<std::mutex> lock(_mutex);**:
  • 这行代码声明了一个名为 lock 的 std::unique_lock 对象,并立即尝试锁定传递给它的 std::mutex 对象 _mutex
  • 如果 _mutex 当前被另一个线程锁定,则此线程将阻塞,直到 _mutex 可用并被成功锁定。
  • 一旦 lock 对象被销毁(通常是在其作用域结束时),它将自动解锁 _mutex

多种类型转换函数

转换函数 用途 语法
static_cast 用于隐式类型转换(提高代码可读性),合理的类型转换,因为它在编译时会进行类型检查。 static_cast<type>(expression)
dynamic_cast 用于在类层次结构中进行安全的向下转换(必须有虚函数)。 dynamic_cast<type>(expression)
const_cast 用于增加或移除变量的 constvolatile 属性。 const_cast<type>(expression)
reinterpret_cast 用于进行低级别的重新解释类型转换。 reinterpret_cast<type>(expression)
std::stoi std::string 转换为 int 类型。 std::stoi(string)
std::stol std::string 转换为 long 类型。 std::stol(string)
std::stoll std::string 转换为 long long 类型。 std::stoll(string)
std::stof std::string 转换为 float 类型。 std::stof(string)
std::stod std::string 转换为 double 类型。 std::stod(string)
std::stold std::string 转换为 long double 类型。 std::stold(string)
std::to_string 将数值类型(intfloatdouble 等)转换为 std::string std::to_string(value)
std::from_chars 将字符数组或字符串转换为数值类型(C++17 引入)。 std::from_chars(ptr, ptr_end, value)
std::to_chars 将数值类型转换为字符数组(C++17 引入)。 std::to_chars(ptr, ptr_end, value)

C11
https://weihehe.top/2024/07/10/C11标准/
作者
weihehe
发布于
2024年7月10日
许可协议