C++11及其之后的新特性

July 01, 2025 作者: funnywii 分类: 编程 浏览: 10 评论: 0

C++11

  1. 自动类型推导

需要注意的是:

  • 必须在定义时初始化auto类型的变量
  • auto类型不能定义数组
  • 一旦初始初始化,就不可更改类型
auto x = 5; 
auto y = 3.14; 
auto a;  // 错误
auto array[10]; //错误
auto a = 10;
a = "ABC"; //错误
  1. for range循环

需要注意的是:

  • 这种循环方式不能使用索引
  • 基于for range循环的遍历是只读遍历,除非将变量类型声明为引用类型。
std::vector<int> v = {1, 2, 3, 4, 5};
for (auto& element : v) {
    std::cout << element << " ";
}
  1. Lambda 表达式

利用Lambda表达式,可以方便的定义和创建匿名函数。声明格式如下:

[capture list] (params list) mutable exception-> return type { function body }
  • [capture list]: 捕获外部变量列表
  • params list: 形参列表
  • mutable: 说明是否可以修改捕获的变量
  • exception: 异常设置
  • return type: 返回值类型
  • {function body}: 函数体

在下面示例中

  • auto lambda 说明为lambda类型变量, lambda不能手动指定类型
  • [x]为捕获外部变量列表
  • (int a, int b)为形参列表, 接受2个整形参数
  • mutable关键字, 说明可以修改捕获的变量
  • throw()表示声明不抛出任何异常
  • -> int说明返回值为一个整型值
  • { x += a + b; return x; }函数体用于实现具体功能, 也就是返回 x = x + (a + b)
auto lambda = [x] (int a, int b) mutable throw() -> int {
    x += a + b;
    return x;
};
std::cout << lambda(3, 4) << std::endl;

再写一个例子, 是一个无捕获的Lambda表达式.

这个很多人一开始看不懂, sort()函数的第3个可选参数是排序方法 comp, 默认情况下是升序, 当 a < b =true 时, sort() 认为 a 应该出现在 b 之前; 当 a < b = false 时, sort() 认为 b 应该出现在 a 之前或两者相等.

std::vector<int> v = {3, 1, 4, 1, 5, 9};
std::sort(v.begin(), v.end(), [](int a, int b) {
    return a < b;
});
  1. 智能指针
std::unique_ptr<int> p1(new int(42)); // 独占所有权, 保证同一时间内只有一个智能指针可以指向该对象。
std::shared_ptr<int> p2 = std::make_shared<int>(42); // 共享所有权, 多个智能指针可以指向相同对象, 该对象和其相关资源会在最后一个引用被销毁时(计数为0)候释放
std::weak_ptr<int> p3 = p2   // weak_ptr只是提供了对管理对象的一个访问手段, 引用对象时引用计数不增加
std::weak_ptr<int> p3 = p1   // 错误, 不能指向unique_ptr
  1. 右值引用和移动语义
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = std::move(v1); // 移动语义,避免深拷贝

左值是一般指表达式结束后依然存在的持久化对象,右值指表达式结束时就不再存在的临时对象。区分左值和右值的便捷方法:能对表达式取地址、有名字的对象为左值。反之,不能取地址、匿名的对象为右值。

  1. 线程库
#include <thread>
void func() {
    std::cout << "Hello thread!" << std::endl;
}
std::thread t(func);
t.join();

C++14

  1. 泛型 Lambda 表达式

C++14的泛型lambda可以被看做C++11的(单态)lambda的升级版, 可以使用 auto关键字来创建一个可以接受任何类型参数的lambda表达式.

要注意的是:

  • 泛型lambda可能接受隐式类型转换
  • 表达式中的操作不支持所有可能的类型时, 类型推导错误进而导致编译错误.
auto add = [](int a, int b) { return a + b; };     // C++11
auto add = [](auto a, auto b) { return a + b; };   // C++14
  1. 返回类型推导
auto func() {
    return 42; // 返回类型自动推导为 int
}
  1. 变量模板

变量模板不是变量,只有实例化的变量模板,编译器才会生成实际的变量。变量模板实例化后简单的说就是一个全局变量,所以也不用担心生存期的问题。

  • 模板函数, 生成类型无关的函数
 template<typename T>
     T max(T a, T b) { return a > b ? a : b; }
  • 模板类, 生成类型无关的类
struct Math {
         static const double pi; // 声明
     };
     const double Math::pi = 3.14159; 
  • 模板变量
template<typename T>
constexpr T pi = T(3.141592653589793238462643383279);

double d = pi<double>;
float f = pi<float>;

是为了代码简洁性, 也支持编译器计算.

  1. 二进制字面量

0b或者 0B开头.

int a = 0b1010; // 二进制字面量 -> 十进制的 10
  1. std::make_unique

std::make_unique 比使用 new 更安全, 因为其可以防止内存泄露, 也可以避免裸指针.

std::unique_ptr<MyClass> ptr1(new MyClass());
std::unique_ptr<MyClass> ptr2=std::make_unique<MyClass>();

C++17

  1. 结构化绑定

可以把 std::pairstd::tuple以及其他具有公开非静态类型的元素绑定到一组变量上. 变量类型是自动推导出来的, 不会出现类型不匹配的问题.

std::pair<int, std::string> p = {42, "hello"};
// 使用tie方法获取p中的元素
int x;
std::string y;
std::tie(x,y) = p;
// 结构化绑定方法获取p中的元素
auto [value, text] = p;

还可以用于遍历 map以及获取有多个返回值函数的返回值:

std::map<int, std::string> m = {{1, "one"}, {2, "two"}};
for (const auto& [key, value] : m) {
    std::cout << key << ": " << value << std::endl;
}

auto getPerson() {
    return std::make_tuple("Alice", 30);
}
auto [name, age] = getPerson();
  1. constexpr if

普通的 if-else 是在执行期进行条件判断与选择, 这意味着在泛型编程中无法使用.

constexpr if 支持在编译期执行, 可以将之应用于泛型编程中的条件判断.

template<typename T>
auto get_value(T t) {
    if constexpr (std::is_integral_v<T>) {
        return t * 2;
    } else {
        return t;
    }
}
  1. 折叠表达式
  2. std::optional

std::optional 表示一个可能有值的对象, 没有值时就返回 std::nullopt.

std::optional<int> find_value() {
    if (condition) {
        return 42;                // 有值, 返回42
    } else {
        return std::nullopt;      // 返回nullpot
    }
}
  1. 文件系统库

可以更方便的进行包括但不限于路径操作, 文件和目录的创建/删除/查询, 获取文件大小和系统空间信息, 目录遍历等操作.

#include <filesystem>

C++20

还没学...

  1. Concepts
  2. Coroutines 协程
  3. Ranges
  4. Modules
  5. 三路比较运算符<=>

参考文章

[1] C++11新特性——auto的使用方法

[2] C++ 11 Lambda表达式 - 滴水瓦 - 博客园

[3] C++ sort排序函数用法-CSDN博客

[4] C++干货系列——右值引用与移动语义 - 知乎

[5] 【C++】右值引用、移动语义、完美转发

[6] 变量模板 | 现代 C++ 模板教程

[7] 深入探索C++智能指针:std::unique_ptr、std::make_unique、std::make_shared与new的对比 - 知乎

[8] C++17尝鲜:结构化绑定声明

[9] C++17 之 "constexpr if"_c++17 constexpr if 表达式-CSDN博客

[10] 折叠表达式 | 现代 C++ 模板教程

[11] C++17 新特性之 std::optional(上) - 知乎

#C++(27)

评论