快速入门现代C++:从C++11到C++20的核心特性

什么是现代C++?

现代C++通常指C++11及之后版本的C++语言。自2011年C++11发布以来,C++发生了革命性的变化,引入了大量让代码更安全、高效、简洁的新特性。本文将带你快速掌握现代C++的核心特性。

一、自动类型推导

1.1 auto 关键字

auto 让编译器自动推导变量类型,使代码更简洁:

cpp 复制代码
// 传统方式
std::vector<int>::iterator it = vec.begin();

// 现代方式
auto it = vec.begin();
auto name = "C++";        // 推导为 const char*
auto score = 95.5;        // 推导为 double
auto numbers = {1, 2, 3}; // 推导为 std::initializer_list<int>

1.2 decltype 关键字

decltype 可以获取表达式的类型:

cpp 复制代码
int x = 10;
decltype(x) y = 20; // y的类型与x相同,即int

std::vector<int> vec;
decltype(vec.begin()) iter; // iter的类型是vector<int>::iterator

二、智能指针:告别手动内存管理

现代C++最重要的改进之一,彻底改变了内存管理方式。

2.1 std::unique_ptr:独占所有权

cpp 复制代码
#include <memory>

void uniquePtrExample() {
    // 创建unique_ptr
    auto ptr = std::make_unique<int>(42);
    
    // 自动管理内存,无需手动delete
    std::cout << *ptr << std::endl;
    
    // 移动语义,所有权转移
    auto ptr2 = std::move(ptr);
    if (!ptr) {
        std::cout << "ptr is now null" << std::endl;
    }
} // 自动释放内存

2.2 std::shared_ptr:共享所有权

cpp 复制代码
void sharedPtrExample() {
    auto shared1 = std::make_shared<std::string>("Hello");
    
    {
        auto shared2 = shared1; // 引用计数+1
        std::cout << *shared2 << std::endl;
    } // shared2析构,引用计数-1
    
    std::cout << *shared1 << std::endl; // 仍然有效
} // shared1析构,引用计数为0,内存释放

2.3 std::weak_ptr:解决循环引用

cpp 复制代码
struct Node {
    std::shared_ptr<Node> next;
    std::weak_ptr<Node> prev; // 使用weak_ptr避免循环引用
};

void weakPtrExample() {
    auto node1 = std::make_shared<Node>();
    auto node2 = std::make_shared<Node>();
    
    node1->next = node2;
    node2->prev = node1; // 不会增加引用计数
}

三、Lambda表达式:匿名函数的威力

Lambda让函数式编程在C++中变得简单:

cpp 复制代码
#include <vector>
#include <algorithm>

void lambdaExample() {
    std::vector<int> numbers = {5, 2, 8, 1, 9};
    
    // 基本lambda
    std::sort(numbers.begin(), numbers.end(), 
              [](int a, int b) { return a < b; });
    
    // 捕获外部变量
    int threshold = 5;
    auto count = std::count_if(numbers.begin(), numbers.end(),
        [threshold](int x) { // 值捕获
            return x > threshold;
        });
    
    // 引用捕获
    int sum = 0;
    std::for_each(numbers.begin(), numbers.end(),
        [&sum](int x) { // 引用捕获
            sum += x;
        });
    
    // 通用lambda (C++14)
    auto genericLambda = [](auto x) { return x * 2; };
    std::cout << genericLambda(5) << ", " << genericLambda(3.14) << std::endl;
}

四、移动语义和右值引用

理解移动语义是现代C++性能优化的关键:

cpp 复制代码
class String {
private:
    char* data;
    size_t length;
    
public:
    // 移动构造函数
    String(String&& other) noexcept 
        : data(other.data), length(other.length) {
        other.data = nullptr;    // "偷走"资源
        other.length = 0;
    }
    
    // 移动赋值运算符
    String& operator=(String&& other) noexcept {
        if (this != &other) {
            delete[] data;        // 释放原有资源
            data = other.data;    // "偷走"资源
            length = other.length;
            other.data = nullptr;
            other.length = 0;
        }
        return *this;
    }
    
    ~String() { delete[] data; }
};

void moveExample() {
    String s1 = createString(); // 假设createString返回临时String
    
    std::vector<String> strings;
    strings.push_back(String("Temporary")); // 移动而非拷贝
    
    String s2 = std::move(s1); // 显式移动
}

五、现代循环和结构化绑定

5.1 基于范围的for循环

cpp 复制代码
void rangeBasedForLoop() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    
    // 只读访问
    for (const auto& num : numbers) {
        std::cout << num << " ";
    }
    
    // 修改元素
    for (auto& num : numbers) {
        num *= 2;
    }
    
    // 遍历map
    std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}};
    for (const auto& [name, score] : scores) { // C++17结构化绑定
        std::cout << name << ": " << score << std::endl;
    }
}

5.2 结构化绑定 (C++17)

cpp 复制代码
std::tuple<int, std::string, double> getPerson() {
    return {25, "Alice", 170.5};
}

void structuredBindingExample() {
    // 传统方式
    auto person = getPerson();
    int age = std::get<0>(person);
    std::string name = std::get<1>(person);
    
    // 现代方式 (C++17)
    auto [age, name, height] = getPerson();
    
    // 用于pair
    std::map<std::string, int> scores;
    auto [iter, success] = scores.insert({"Alice", 95});
    
    // 用于结构体
    struct Point { double x, y; };
    Point p{1.0, 2.0};
    auto [x, y] = p;
}

六、可选类型和变体类型

6.1 std::optional:可能不存在的值

cpp 复制代码
#include <optional>

std::optional<int> findNumber(const std::vector<int>& vec, int target) {
    auto it = std::find(vec.begin(), vec.end(), target);
    if (it != vec.end()) {
        return *it; // 返回值
    }
    return std::nullopt; // 无值
}

void optionalExample() {
    std::vector<int> numbers = {1, 3, 5, 7, 9};
    
    auto result = findNumber(numbers, 5);
    
    if (result.has_value()) { // 或者 if (result)
        std::cout << "Found: " << result.value() << std::endl;
        std::cout << "Found: " << *result << std::endl; // 也可以解引用
    } else {
        std::cout << "Not found" << std::endl;
    }
    
    // 提供默认值
    int value = result.value_or(-1);
}

6.2 std::variant:类型安全的联合体

cpp 复制代码
#include <variant>

void variantExample() {
    std::variant<int, std::string, double> value;
    
    value = 42; // 存储int
    value = "Hello"; // 存储string
    value = 3.14; // 存储double
    
    // 访问值
    if (std::holds_alternative<int>(value)) {
        std::cout << "int: " << std::get<int>(value) << std::endl;
    }
    
    // 使用visit (C++17)
    std::visit([](auto&& arg) {
        using T = std::decay_t<decltype(arg)>;
        if constexpr (std::is_same_v<T, int>) {
            std::cout << "int: " << arg << std::endl;
        } else if constexpr (std::is_same_v<T, std::string>) {
            std::cout << "string: " << arg << std::endl;
        } else if constexpr (std::is_same_v<T, double>) {
            std::cout << "double: " << arg << std::endl;
        }
    }, value);
}

七、编译时计算:constexpr 的威力

cpp 复制代码
// constexpr函数可以在编译期计算
constexpr int factorial(int n) {
    return (n <= 1) ? 1 : (n * factorial(n - 1));
}

// constexpr变量在编译期初始化
constexpr int max_size = 100;

void constexprExample() {
    int array[factorial(5)]; // 数组大小在编译期计算
    
    constexpr int result = factorial(5); // 编译期计算
    std::cout << "5! = " << result << std::endl;
}

// C++20 consteval - 必须编译期求值
consteval int square(int n) {
    return n * n;
}

八、实际应用示例

让我们用一个完整的例子展示现代C++的特性:

cpp 复制代码
#include <iostream>
#include <memory>
#include <vector>
#include <algorithm>
#include <optional>
#include <ranges>

class Student {
private:
    std::string name;
    int score;
    
public:
    Student(std::string n, int s) : name(std::move(n)), score(s) {}
    
    // 移动构造函数
    Student(Student&& other) noexcept 
        : name(std::move(other.name)), score(other.score) {}
    
    const std::string& getName() const { return name; }
    int getScore() const { return score; }
};

class GradeManager {
private:
    std::vector<std::unique_ptr<Student>> students;
    
public:
    void addStudent(std::string name, int score) {
        students.push_back(std::make_unique<Student>(std::move(name), score));
    }
    
    std::optional<int> findScore(const std::string& name) const {
        auto it = std::find_if(students.begin(), students.end(),
            [&name](const auto& student) {
                return student->getName() == name;
            });
        
        if (it != students.end()) {
            return (*it)->getScore();
        }
        return std::nullopt;
    }
    
    void printTopStudents(int threshold) const {
        // 使用ranges和lambda (C++20)
        auto topStudents = students | std::views::filter([threshold](const auto& student) {
            return student->getScore() >= threshold;
        });
        
        for (const auto& student : topStudents) {
            std::cout << student->getName() << ": " << student->getScore() << std::endl;
        }
    }
};

int main() {
    GradeManager manager;
    
    manager.addStudent("Alice", 95);
    manager.addStudent("Bob", 87);
    manager.addStudent("Charlie", 92);
    
    // 查找成绩
    if (auto score = manager.findScore("Alice")) {
        std::cout << "Alice's score: " << *score << std::endl;
    }
    
    // 打印优秀学生
    std::cout << "Top students:" << std::endl;
    manager.printTopStudents(90);
    
    return 0;
}

学习建议

  1. 循序渐进:从C++11开始,逐步学习C++14、C++17、C++20的新特性
  2. 实践为主:在实际项目中应用这些特性
  3. 理解原理:特别是移动语义和智能指针的工作原理
  4. 关注性能:现代C++的很多特性都是为了更好的性能

现代C++让编程变得更安全、更高效、更愉快。掌握这些核心特性,你将能够编写出更现代化的C++代码!

相关推荐
码事漫谈2 小时前
深入解析进程间通信(IPC)及其应用场景
后端
ejinxian2 小时前
ASP.NET Core 10
后端·asp.net·core 10
用户21411832636023 小时前
Claude Skills 硬核技巧:用 PDF-Skill 10 分钟搞定全类型 PDF 自动化,办公人必备
后端
大橙子打游戏3 小时前
mp4文件在CDN上无法在网页播放的问题
后端
q***78785 小时前
Spring Boot的项目结构
java·spring boot·后端
转转技术团队5 小时前
分页查询的稳定性陷阱与根治方案
后端·mysql·elasticsearch
百***17075 小时前
Spring Boot spring.factories文件详细说明
spring boot·后端·spring
倚肆6 小时前
HttpServletResponse 与 ResponseEntity 详解
java·后端·spring
虎子_layor6 小时前
告别JMeter!我用 k6 5 分钟完成高并发压测
后端·测试