跳到主要内容

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 的更新主要集中在以下几个方面:

  1. 提高语言核心可用性:让语言更加易用、表达性更强
  2. 提升运行时性能:引入更高效的编程模型和性能优化
  3. 加强抽象能力:改进类型系统和泛型编程
  4. 增强并发支持:提供标准的多线程支持

核心语言特性

自动类型推导 (auto)

auto 关键字允许编译器自动推导变量的类型,减少冗长的类型声明。

cpp
// C++98/03 方式
std::vector<int>::iterator it = vec.begin();

// C++11 方式
auto it = vec.begin(); // 编译器自动推导 it 的类型

基于范围的 for 循环

C++11 提供了一种更简洁的遍历容器的方法。

cpp
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 表达式允许在代码中定义匿名函数,简化代码并提高可读性。

cpp
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 宏,解决了一些类型安全问题。

cpp
// 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 引入了限定作用域的枚举类型,解决了传统枚举的一些问题。

cpp
// 传统枚举,枚举常量泄漏到外部作用域
enum Color { RED, GREEN, BLUE };

// C++11 强类型枚举
enum class NewColor { Red, Green, Blue };

Color c1 = RED; // 正确,但枚举常量在全局作用域
NewColor c2 = NewColor::Red; // 必须使用作用域限定符

现代 C++ 核心功能

移动语义与右值引用

移动语义是 C++11 的重要改进之一,它通过右值引用 (&&) 实现高效的资源转移而非复制。

cpp
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 引入了几种智能指针,大大简化了内存管理,避免内存泄漏。

cpp
// 独占所有权的智能指针
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 引入了花括号初始化语法,提供了一种统一的初始化方式。

cpp
// 基本类型初始化
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 首次在标准库中提供了原生的多线程支持。

cpp
#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 增加了几种新的容器和功能:

cpp
// 无序关联容器(基于哈希表)
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 增加了对正则表达式的标准支持。

cpp
#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 关键字允许在编译期计算表达式值,提高程序性能。

cpp
constexpr int factorial(int n) {
return n <= 1 ? 1 : (n * factorial(n - 1));
}

// 编译期计算
constexpr int result = factorial(5); // 在编译时计算 5! = 120

decltype

decltype 用于获取表达式的类型,增强了泛型编程的能力。

cpp
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 允许为字面量定义自己的后缀,增强表达能力。

cpp
// 定义自己的字面量后缀
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:使用智能指针管理资源

cpp
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:使用线程库实现并行计算

cpp
#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:

  1. 显著提高了代码的可读性和可维护性
  2. 减少了常见的内存错误和资源泄漏
  3. 增强了抽象能力和表达能力
  4. 提供了标准化的并发编程支持
  5. 为后续的 C++14、C++17 和 C++20 等版本的演进铺平了道路

总结

C++11 引入的诸多新特性使 C++ 成为一种更现代、更高效、更安全的编程语言。这些新特性包括自动类型推导、范围 for 循环、Lambda 表达式、智能指针、移动语义等。掌握这些特性对于编写现代 C++ 程序至关重要,也是理解后续 C++ 标准的基础。

在学习现代 C++ 时,建议先深入理解 C++11 的核心概念,然后再逐步学习 C++14、C++17 和 C++20 引入的其他特性。

练习

  1. 使用 auto 和范围 for 循环,编写一个函数来计算向量中所有偶数的和。
  2. 使用 Lambda 表达式,对一个包含字符串的向量按字符串长度排序。
  3. 实现一个简单的智能指针类,包含基本的构造、析构和解引用操作。
  4. 使用 std::thread 创建两个线程,一个线程打印奇数,另一个线程打印偶数。
  5. 使用 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++ 语言和标准库参考