C++11/14/17/20 中引入了哪些新特性?

C++11、C++14、C++17和C++20是C++语言标准的四个重要版本,每个版本都引入了多项新特性,旨在提高语言的表达力、性能和易用性。以下是这些版本中引入的一些关键新特性的概述:

C++11

  • 列表初始化:允许使用花括号 {} 来初始化对象,使得初始化更加直观和一致。
#include <vector>
std::vector<int> vec = {1, 2, 3};
  • 类型推导:通过 auto 关键字和 decltype 关键字简化类型声明,使得编译器能够自动推导变量类型。
auto num = 10; // num 的类型被推导为 int
  • 基于范围的 for 循环:提供了一种新的方式来遍历容器和数组,使得循环更加简洁。
for (auto const& value : vec) {
    // 使用 value
}
  • 初始化列表std::initializer_list 允许类使用初始化列表作为构造函数的参数,提供了统一的初始化方式。
class Point{
public:
	Point(int x_, int y_):x(x_),y(y_){};
private:
	int x, y;
};
  • 右值引用和移动语义:引入了右值引用 &&,允许开发者更有效地处理临时对象,减少不必要的拷贝,提高性能。
#include <string>
std::string str = std::move(otherStr); // 使用 move 语义避免不必要的拷贝
  • 智能指针:如 std::unique_ptrstd::shared_ptr,提供了自动内存管理,减少内存泄漏的风险。
#include <memory>
std::unique_ptr<int> uniquePtr(new int(10));
std::shared_ptr<int> sharedPtr(new int(10), [](int* p) { delete p; });
  • lambda 表达式:允许在代码中定义匿名函数,增加了编程的灵活性。
auto square = [](int x) { return x * x; };
  • 并发编程:引入了线程库,提供了语言级别的线程支持。

C++11引入了对线程和并发编程的原生支持,这使得编写多线程程序变得更加容易和高效。以下是C++11并发编程的一些基本示例:

1. 创建线程

#include <iostream>
#include <thread>
#include <vector>

void printID() {
    // 打印当前线程的ID
    std::cout << "Thread ID: " << std::this_thread::get_id() << '\n';
}

int main() {
    // 创建线程对象
    std::thread t1(printID);
    
    // 调用printID函数
    t1.join(); // 等待线程t1结束

    // 创建多个线程
    std::vector<std::thread> threads;
    for (int i = 0; i < 5; ++i) {
        threads.emplace_back(printID);
    }

    // 等待所有线程结束
    for(auto &th : threads) {
        th.join();
    }

    return 0;
}

2. 使用 std::async

std::async 用于并行执行任务,并可以异步地获取返回结果。

#include <future>
#include <iostream>

int someCalculation(int x) {
    // 模拟计算
    return x * x;
}

int main() {
    auto result = std::async(someCalculation, 4); // 异步调用someCalculation

    // 执行其他工作...

    if (result.valid()) {
        std::cout << "Result: " << result.get() << std::endl; // 获取结果
    }

    return 0;
}

3. 互斥锁 std::mutex

互斥锁用于保护共享资源不被多个线程同时访问。

#include <iostream>
#include <mutex>
#include <thread>

std::mutex mu;
int counter = 0;

void increment() {
    for (int i = 0; i < 100000; ++i) {
        std::lock_guard<std::mutex> lock(mu); // 锁定互斥锁
        ++counter;
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Counter: " << counter << std::endl; // 打印结果

    return 0;
}

4. 原子操作 std::atomic

原子操作提供了一种无需使用互斥锁的方式来保证线程间的数据一致性。

#include <atomic>
#include <thread>

std::atomic<int> counter(0); // 使用std::atomic封装原子型变量

void increment() {
    for (int i = 0; i < 100000; ++i) {
        ++counter; // 原子操作,自动保证线程安全
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Counter: " << counter << std::endl;

    return 0;
}

5. 条件变量 std::condition_variable

条件变量用于在线程之间同步共享资源的条件。

#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void worker() {
    std::unique_lock<std::mutex> lck(mtx);
    cv.wait(lck, []{ return ready; }); // 等待条件变量
    // 临界区
    std::cout << "Item processed by " << std::this_thread::get_id() << '\n';
}

void starter() {
    std::unique_lock<std::mutex> lck(mtx);
    ready = true;
    cv.notify_all(); // 通知所有等待的线程
}

int main() {
    std::thread t1(worker);
    std::thread t2(starter);

    t1.join();
    t2.join();

    return 0;
}

这些示例展示了C++11中并发编程的一些基本工具和模式。使用这些工具,你可以创建和管理多线程程序,同步线程间的操作,并安全地访问共享资源。

C++14

  • 二进制字面量:允许使用 0b 前缀来表示二进制数值。
int binaryValue = 0b10; // 十进制的 2
  • 泛型 lambda 表达式:允许在 lambda 表达式中使用 auto 关键字来推导类型。
auto print = [](auto x) { std::cout << x << std::endl; };
  • 返回类型推导:允许在函数声明中省略返回类型,编译器会根据函数体中的 return 语句来推导返回类型。
auto func(int x) -> int {
    return x * 2;
}
  • 变量模板:允许模板参数为非类型参数,例如,你可以创建一个模板变量,它在实例化时可以提供类型。
template <typename T>
constexpr T pi = T(3.14159265358979323846);
  • 编译器诊断:增强了编译器的错误和警告信息,使其更加有用。

  • 标准库中的新组件:如 std::make_uniquestd::shared_timed_mutex

C++17

  • 结构化绑定:允许从元组、对和类中提取多个成员,简化了数据结构的使用。
std::pair<int, std::string> p(1, "one");
auto [num, word] = p; // num 为 int,word 为 std::string
  • if-constexpr:允许在 if 语句中使用 constexpr 表达式,从而在编译时计算条件。
template <typename T>
constexpr bool is_even(int number) {
    if constexpr (number % 2 == 0) {
        return true;
    } else {
        return false;
    }
}
  • 嵌套命名空间:允许在命名空间中直接使用 namespace 关键字来定义嵌套命名空间,简化了命名空间的使用。
  • 文件系统库:引入了 std::filesystem 库,提供了一套完整的文件系统操作功能。
#include <filesystem>
namespace fs = std::filesystem;
fs::path p = "/path/to/file"; // 使用文件系统库
  • 平行算法:标准库中的算法有了并行版本的实现,允许利用多核处理器的计算能力。
  • std::variant 和 std::optional:提供了对类型安全联合(variant)和可选类型(optional)的支持。
#include <optional>
std::optional<int> opt = 10;
if (opt) {
    // opt 有值
}

C++20

  • 概念(Concepts):允许定义模板参数的约束,使得模板编程更加灵活和安全。
template <typename T>
concept Integral = requires {
    typename T::value_type;
};
  • 模块(Modules):提供了一种新的编译单元,可以改善编译时间和代码组织。
// example.cppm
export module example;
export int foo() {
    return 42;
}
  • 协程(Coroutines):引入了对异步编程和协程的支持。
在这里插入代码片
  • 范围库改进:如 std::ranges,提供了对范围的算法支持。
C++20标准引入了`std::ranges`命名空间,它提供了一系列工具和算法,用于处理符合新标准中定义的“范围”概念的序列。这些范围可以是数组、向量(`std::vector`)、双端队列(`std::deque`)、字符串(`std::string`)、映射(`std::map`)等,以及任何符合范围概念的自定义序列。

范围库的核心是`std::range`,它是一个模板类,提供了对各种范围类型的支持。此外,C++20还引入了“视图”(views),它们是不可修改的、惰性的范围,可以对原始范围进行切片、打乱或重新排列,而不改变原始数据。

以下是一些C++20中`std::ranges`的使用示例:

### 1. 范围for循环

C++20扩展了基于范围的for循环,允许直接对符合范围概念的序列进行迭代。

```cpp
#include <vector>
#include <ranges>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    for (auto num : vec) {
        std::cout << num << ' ';
    }
    std::cout << '\n';
}

2. 范围算法

C++20提供了新的范围算法,如ranges::find_ifranges::sort等,这些算法可以直接在范围上工作。

#include <ranges>
#include <iostream>

int main() {
    std::vector<int> vec = {3, 1, 4, 1, 5, 9, 2};
    
    auto it = std::ranges::find_if(vec, [](int i) { return i > 5; });
    if (it != vec.end()) {
        std::cout << "Found a number greater than 5: " << *it << '\n';
    } else {
        std::cout << "No number greater than 5 found.\n";
    }
    
    std::ranges::sort(vec);
    
    std::cout << "Sorted vector: ";
    for (int num : vec) {
        std::cout << num << ' ';
    }
    std::cout << '\n';
}

3. 范围视图

C++20的范围视图提供了一种无需复制数据的方式来处理范围。例如,std::ranges::views::transform可以用来创建一个转换序列中每个元素的新视图。

#include <ranges>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    
    auto squared_view = vec | std::ranges::views::transform([](int i) { return i * i; });
    
    std::cout << "Squared view: ";
    for (int num : squared_view) {
        std::cout << num << ' ';
    }
    std::cout << '\n';
}

在这个例子中,我们使用了std::ranges::views::transform视图和C++20的管道操作符|来创建一个新的视图,该视图包含原始向量中每个元素的平方。

C++20的范围库和视图提供了一种强大且表达性极强的新方式来处理序列,它们是C++标准库中非常令人激动的新特性。


- **空间ship 运算符**:`<=>` 用于定义三元顺序关系,简化了比较函数的编写。
- **改进的 constexpr**:进一步放宽了 `constexpr` 的限制,允许更多的编译时计算。

```cpp
constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}
  • 原子访问的 volatile 类型:提供了对并发和易变性的更好支持。

这些新特性的引入,使得C++语言在表达力、性能和易用性上都有了显著的提升,同时也为C++的未来发展奠定了基础。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值