什么是现代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;
}
学习建议
- 循序渐进:从C++11开始,逐步学习C++14、C++17、C++20的新特性
- 实践为主:在实际项目中应用这些特性
- 理解原理:特别是移动语义和智能指针的工作原理
- 关注性能:现代C++的很多特性都是为了更好的性能
现代C++让编程变得更安全、更高效、更愉快。掌握这些核心特性,你将能够编写出更现代化的C++代码!