39、Cpp常用新特性

厨子大约 4 分钟C++C++基础编程程序厨

C++现在基本是每三年引入一些新特性,C++11、C++14、C++17和C++20引入了许多进阶特性,极大地提升了C++的灵活性和开发效率。

本文会详细介绍主要的新特性。

右值引用与移动语义

右值引用的概念

右值引用是C++11引入的一种引用类型,用于绑定临时对象(右值)。右值引用的语法为T&&

移动语义

移动语义是指将资源(如内存)从一个对象转移到另一个对象,而不是复制资源。

合理使用移动语义,可以避免不必要的复制操作,提高性能。

代码示例

#include <iostream>
#include <vector>

class MyClass {
public:
    MyClass() { std::cout << "MyClass constructed." << std::endl; }
    ~MyClass() { std::cout << "MyClass destroyed." << std::endl; }

    // 移动构造函数
    MyClass(MyClass&& other) noexcept {
        std::cout << "MyClass moved." << std::endl;
    }

    // 移动赋值运算符
    MyClass& operator=(MyClass&& other) noexcept {
        std::cout << "MyClass move-assigned." << std::endl;
        return *this;
    }
};

int main() {
    MyClass obj1;
    MyClass obj2 = std::move(obj1); // 调用移动构造函数
    MyClass obj3;
    obj3 = std::move(obj2); // 调用移动赋值运算符
    return 0;
}

std::move

std::move用于将对象转换为右值引用,从而触发移动语义

代码示例

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec1 = {1, 2, 3};
    std::vector<int> vec2 = std::move(vec1); // 使用std::move触发移动语义

    std::cout << "vec1 size: " << vec1.size() << std::endl; // 输出:0
    std::cout << "vec2 size: " << vec2.size() << std::endl; // 输出:3

    return 0;
}

完美转发与std::forward

完美转发的概念

完美转发是指在函数模板中将参数以**原始类型(左值或右值)**转发给另一个函数。

std::forward

std::forward用于在函数模板中实现完美转发。

代码示例

#include <iostream>

void func(int& x) {
    std::cout << "Lvalue reference: " << x << std::endl;
}

void func(int&& x) {
    std::cout << "Rvalue reference: " << x << std::endl;
}

template <typename T>
void wrapper(T&& arg) {
    func(std::forward<T>(arg)); // 使用std::forward实现完美转发
}

int main() {
    int x = 10;
    wrapper(x); // 调用func(int&)
    wrapper(20); // 调用func(int&&)
    return 0;
}

并发编程

std::thread

std::thread是C++11引入的线程类,用于创建和管理线程。

代码示例

#include <iostream>
#include <thread>

void threadFunc() {
    std::cout << "Hello from thread!" << std::endl;
}

int main() {
    std::thread t(threadFunc); // 创建线程
    t.join(); // 等待线程结束
    return 0;
}

std::mutex

std::mutex是C++11引入的互斥量类,用于保护共享资源。

代码示例

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

std::mutex mtx;

void threadFunc(int id) {
    std::lock_guard<std::mutex> lock(mtx); // 自动加锁和解锁
    std::cout << "Thread " << id << " is running." << std::endl;
}

int main() {
    std::thread t1(threadFunc, 1);
    std::thread t2(threadFunc, 2);
    t1.join();
    t2.join();
    return 0;
}

std::future与std::async

std::futurestd::async用于异步任务和获取结果。

代码示例

#include <iostream>
#include <future>

int asyncFunc() {
    return 42;
}

int main() {
    std::future<int> fut = std::async(asyncFunc); // 启动异步任务
    int result = fut.get(); // 获取结果
    std::cout << "Result: " << result << std::endl; // 输出:42
    return 0;
}

新增的数据类型与语法特性

std::optional(C++17)

std::optional用于表示可能不存在的值,我经常使用。

代码示例

#include <iostream>
#include <optional>

std::optional<int> divide(int a, int b) {
    if (b == 0) {
        return std::nullopt; // 表示无值
    }
    return a / b;
}

int main() {
    auto result = divide(10, 2);
    if (result) {
        std::cout << "Result: " << *result << std::endl; // 输出:5
    } else {
        std::cout << "Division by zero!" << std::endl;
    }
    return 0;
}

std::variant(C++17)

std::variant用于表示多种类型的值。

代码示例

#include <iostream>
#include <variant>
#include <string>

int main() {
    std::variant<int, double, std::string> v = 3.14;
    if (std::holds_alternative<double>(v)) {
        std::cout << "Double value: " << std::get<double>(v) << std::endl; // 输出:3.14
    }
    return 0;
}

结构化绑定(C++17)

结构化绑定用于将结构体或元组的成员绑定到变量。

代码示例

#include <iostream>
#include <tuple>
#include <string>

int main() {
    std::tuple<int, double, std::string> t = {1, 3.14, "Hello"};
    auto [x, y, z] = t; // 结构化绑定
    std::cout << "x = " << x << ", y = " << y << ", z = " << z << std::endl; // 输出:x = 1, y = 3.14, z = Hello
    return 0;
}

if与switch的初始化语句(C++17)

C++17允许在ifswitch语句中定义变量。

代码示例

#include <iostream>

int main() {
    if (int x = 10; x > 5) {
        std::cout << "x is greater than 5: " << x << std::endl; // 输出:x is greater than 5: 10
    }
    return 0;
}

练习

  1. 使用移动语义实现一个简单的字符串类。
  2. 使用std::threadstd::mutex实现一个多线程计数器。
  3. 使用std::optional实现一个安全的除法函数。
  4. 使用std::variant实现一个简单的类型安全的联合体。