C++ 11概述
引言
C++11 是 C++ 编程语言的一个重要版本更新,于2011年发布。它引入了许多新特性和改进,显著提升了 C++ 的表达能力、性能和安全性。作为 C++98/03 之后的首个主要更新,C++11 标志着 C++ 语言的现代化转型,使得编写高效、清晰和安全的代码变得更加容易。
C++11 之前,C++ 标准通常被称为 C++98 或 C++03(2003年的小更新)。而 C++11 之后,C++ 标准委员会决定采用年份命名方式,后续有 C++14、C++17、C++20 等版本。
C++ 11 的主要改进方向
C++11 的更新主要集中在以下几个方面:
- 提高语言核心可用性:让语言更加易用、表达性更强
- 提升运行时性能:引入更高效的编程模型和性能优化
- 加强抽象能力:改进类型系统和泛型编程
- 增强并发支持:提供标准的多线程支持
核心语言特性
自动类型推导 (auto)
auto
关键字允许编译器自动推导变量的类型,减少冗长的类型声明。
// C++98/03 方式
std::vector<int>::iterator it = vec.begin();
// C++11 方式
auto it = vec.begin(); // 编译器自动推导 it 的类型
基于范围的 for 循环
C++11 提供了一种更简洁的遍历容器的方法。
std::vector<int> numbers = {1, 2, 3, 4, 5};
// C++98/03 方式
for (std::vector<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " ";
}
// C++11 方式
for (int n : numbers) {
std::cout << n << " ";
}
// 输出(两种方式相同): 1 2 3 4 5
Lambda 表达式
Lambda 表达式允许在代码中定义匿名函数,简化代码并提高可读性。
std::vector<int> numbers = {4, 1, 3, 5, 2};
// C++11 之前,需要定义函数或函数对象
bool sortFunction(int a, int b) {
return a < b;
}
// C++11 使用 lambda 表达式
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a < b;
});
// 打印排序后的结果: 1 2 3 4 5
for (int n : numbers) {
std::cout << n << " ";
}
nullptr
C++11 引入了 nullptr
来替代表示空指针的 NULL
宏,解决了一些类型安全问题。
// C++98/03 方式(可能导致歧义)
void func(int);
void func(char*);
func(NULL); // 歧义:可能调用 func(int) 而非 func(char*)
// C++11 方式
func(nullptr); // 明确调用 func(char*)
强类型枚举 (enum class)
C++11 引入了限定作用域的枚举类型,解决了传统枚举的一些问题。
// 传统枚举,枚举常量泄漏到外部作用域
enum Color { RED, GREEN, BLUE };
// C++11 强类型枚举
enum class NewColor { Red, Green, Blue };
Color c1 = RED; // 正确,但枚举常量在全局作用域
NewColor c2 = NewColor::Red; // 必须使用作用域限定符
现代 C++ 核心功能
移动语义与右值引用
移动语义是 C++11 的重要改进之一,它通过右值引用 (&&
) 实现高效的资源转移而非复制。
class MyString {
private:
char* data;
size_t size;
public:
// 移动构造函数
MyString(MyString&& other) noexcept
: data(other.data), size(other.size) {
other.data = nullptr; // 资源已转移,防止被销毁
other.size = 0;
}
};
// 使用移动语义
MyString createString() {
return MyString("Hello"); // 返回临时对象(右值)
}
MyString s = createString(); // 调用移动构造而非复制构造
智能指针
C++11 引入了几种智能指针,大大简化了内存管理,避免内存泄漏。
// 独占所有权的智能指针
std::unique_ptr<int> p1 = std::make_unique<int>(42); // C++14 才有 make_unique
std::unique_ptr<int> p2(new int(42)); // C++11 写法
// 共享所有权的智能指针
std::shared_ptr<int> sp1 = std::make_shared<int>(100);
std::shared_ptr<int> sp2 = sp1; // 两个指针共享同一资源
std::cout << "引用计数: " << sp1.use_count() << std::endl; // 输出: 引用计数: 2
// 弱引用的智能指针
std::weak_ptr<int> wp = sp1; // 不增加引用计数
统一初始化语法
C++11 引入了花括号初始化语法,提供了一种统一的初始化方式。
// 基本类型初始化
int a{10};
double b{5.2};
// 容器初始化
std::vector<int> vec{1, 2, 3, 4, 5};
// 自定义类型初始化
struct Point {
int x, y;
};
Point p{10, 20};
标准库增强
线程支持库
C++11 首次在标准库中提供了原生的多线程支持。
#include <thread>
#include <mutex>
#include <iostream>
std::mutex mtx; // 互斥锁,防止数据竞争
void printNumbers(int id) {
for (int i = 0; i < 5; ++i) {
// 使用锁保护共享资源(cout)
std::lock_guard<std::mutex> lock(mtx);
std::cout << "线程 " << id << ": " << i << std::endl;
}
}
int main() {
std::thread t1(printNumbers, 1);
std::thread t2(printNumbers, 2);
t1.join(); // 等待线程完成
t2.join();
return 0;
}
新的容器和算法
C++11 增加了几种新的容器和功能:
// 无序关联容器(基于哈希表)
std::unordered_map<std::string, int> scores;
scores["Alice"] = 95;
scores["Bob"] = 87;
// 数组容器
std::array<int, 5> arr = {1, 2, 3, 4, 5}; // 固定大小的数组
// 元组
std::tuple<int, std::string, double> person(30, "John", 175.5);
std::cout << "姓名: " << std::get<1>(person) << std::endl; // 输出: 姓名: John
正则表达式库
C++11 增加了对正则表达式的标准支持。
#include <regex>
#include <iostream>
#include <string>
int main() {
std::string text = "Email: example@domain.com and another@test.org";
std::regex email_pattern(R"((\w+)@(\w+)\.(\w+))"); // 原始字符串字面量
std::smatch matches;
std::string::const_iterator searchStart(text.begin());
while (std::regex_search(searchStart, text.end(), matches, email_pattern)) {
std::cout << "找到邮箱: " << matches[0] << std::endl;
std::cout << " 用户名: " << matches[1] << std::endl;
std::cout << " 域名: " << matches[2] << "." << matches[3] << std::endl;
searchStart = matches.suffix().first;
}
return 0;
}
/* 输出:
找到邮箱: example@domain.com
用户名: example
域名: domain.com
找到邮箱: another@test.org
用户名: another
域名: test.org
*/
其他重要特性
constexpr
constexpr
关键字允许在编译期计算表达式值,提高程序性能。
constexpr int factorial(int n) {
return n <= 1 ? 1 : (n * factorial(n - 1));
}
// 编译期计算
constexpr int result = factorial(5); // 在编译时计算 5! = 120
decltype
decltype
用于获取表达式的类型,增强了泛型编程的能力。
int a = 10;
decltype(a) b = 20; // b 的类型与 a 相同,即 int
auto add = [](int x, int y) { return x + y; };
decltype(add(1, 2)) result = add(10, 20); // result 的类型是 int
用户定义字面量
C++11 允许为字面量定义自己的后缀,增强表达能力。
// 定义自己的字面量后缀
constexpr long double operator"" _kg(long double weight) {
return weight * 1000; // 转换为克
}
void showWeight() {
auto weight = 5.0_kg; // 相当于 5.0 * 1000
std::cout << "重量: " << weight << " 克" << std::endl; // 输出: 重量: 5000 克
}
实际应用案例
案例1:使用智能指针管理资源
class ResourceManager {
private:
std::shared_ptr<Resource> resource;
public:
ResourceManager() : resource(std::make_shared<Resource>()) {
std::cout << "资源已创建" << std::endl;
}
void useResource() {
if (resource) {
resource->doSomething();
}
}
};
// 多个对象可以安全地共享同一个资源,当最后一个引用销毁时,资源自动释放
案例2:使用线程库实现并行计算
#include <thread>
#include <vector>
#include <numeric>
#include <iostream>
void parallelSum(const std::vector<int>& data, size_t start, size_t end, int& result) {
result = std::accumulate(data.begin() + start, data.begin() + end, 0);
}
int main() {
std::vector<int> data(10000);
for (size_t i = 0; i < data.size(); ++i) {
data[i] = i + 1;
}
const size_t numThreads = 4;
std::vector<std::thread> threads;
std::vector<int> partialSums(numThreads);
size_t chunkSize = data.size() / numThreads;
// 创建多个线程进行并行计算
for (size_t i = 0; i < numThreads; ++i) {
size_t start = i * chunkSize;
size_t end = (i == numThreads - 1) ? data.size() : (i + 1) * chunkSize;
threads.emplace_back(parallelSum, std::ref(data), start, end, std::ref(partialSums[i]));
}
// 等待所有线程完成
for (auto& t : threads) {
t.join();
}
// 汇总结果
int totalSum = std::accumulate(partialSums.begin(), partialSums.end(), 0);
std::cout << "总和: " << totalSum << std::endl;
return 0;
}
C++ 11 的重要性
C++11 是 C++ 发展历程中具有里程碑意义的一次更新,它使 C++ 语言焕发了新的活力,并为现代 C++ 编程奠定了基础。通过引入这些现代特性,C++11:
- 显著提高了代码的可读性和可维护性
- 减少了常见的内存错误和资源泄漏
- 增强了抽象能力和表达能力
- 提供了标准化的并发编程支持
- 为后续的 C++14、C++17 和 C++20 等版本的演进铺平了道路
总结
C++11 引入的诸多新特性使 C++ 成为一种更现代、更高效、更安全的编程语言。这些新特性包括自动类型推导、范围 for 循环、Lambda 表达式、智能指针、移动语义等。掌握这些特性对于编写现代 C++ 程序至关重要,也是理解后续 C++ 标准的基础。
在学习现代 C++ 时,建议先深入理解 C++11 的核心概念,然后再逐步学习 C++14、C++17 和 C++20 引入的其他特性。
练习
- 使用
auto
和范围 for 循环,编写一个函数来计算向量中所有偶数的和。 - 使用 Lambda 表达式,对一个包含字符串的向量按字符串长度排序。
- 实现一个简单的智能指针类,包含基本的构造、析构和解引用操作。
- 使用
std::thread
创建两个线程,一个线程打印奇数,另一个线程打印偶数。 - 使用 C++11 的移动语义优化一个管理大数组的类。
进一步学习的资源
- 《C++ Primer》(第5版) - 全面介绍 C++11 特性
- 《Effective Modern C++》 - Scott Meyers 著,深入讲解如何有效使用 C++11/14
- 《A Tour of C++》 - Bjarne Stroustrup(C++ 创始人)著,简洁地介绍现代 C++
- cppreference.com - 详细的 C++ 语言和标准库参考