C++11新特性解析:现代C++的起点

C++11是现代C++的转折点,引入了大量革命性的特性,被业界称为"C++复兴"。本文将解析C++11的核心特性,包括语法示例和使用场景。

一、auto 和 decltype:类型推导的革命

auto 关键字

基本语法

1
2
3
4
5
6
7
8
9
// 自动推导类型
auto i = 42; // int
auto d = 3.14; // double
auto s = "hello"; // const char*
auto v = vector<int>(); // std::vector<int>

// 与引用和const结合
const auto& cr = i; // const int&
auto& r = i; // int&

使用场景

  • 复杂类型:当类型名称很长时,auto可以简化代码

    1
    2
    3
    4
    // 简化复杂类型
    std::map<std::string, std::vector<int>>::iterator it = map.begin();
    // 简化为
    auto it = map.begin();
  • 模板编程:在模板中推导返回类型

    1
    2
    3
    4
    template<typename T, typename U>
    auto add(T t, U u) -> decltype(t + u) {
    return t + u;
    }
  • lambda表达式:lambda的类型是唯一的,只能用auto捕获

    1
    auto func = [](int x) { return x * 2; };

decltype 关键字

基本语法

1
2
3
4
5
6
7
8
9
10
// 推导表达式类型
int x = 5;
decltype(x) y = 10; // y是int类型

double f();
decltype(f()) z = 3.14; // z是double类型

// 推导引用类型
int& rx = x;
decltype(rx) ry = x; // ry是int&

使用场景

  • 模板返回类型:在C++11中,需要使用尾置返回类型
    1
    2
    3
    4
      template<typename Container, typename Index>
    auto access(Container& c, Index i) -> decltype(c[i]) {
    return c[i]; // 保持返回类型与容器的operator[]一致
    }

二、Lambda表达式:匿名函数的力量

语法结构

1
2
3
4
5
6
7
8
// 基本形式
[capture](parameters) -> return_type { body }

// 省略返回类型(自动推导)
[capture](parameters) { body }

// 无参数
[capture]() { body }

捕获列表

捕获方式 描述
[] 无捕获
[var] 值捕获var
[&var] 引用捕获var
[=] 值捕获所有外部变量
[&] 引用捕获所有外部变量

使用场景

  • STL算法:作为谓词或回调函数

    1
    2
    3
    4
    5
    6
    7
    8
    std::vector<int> nums = {1, 2, 3, 4, 5};
    // 查找第一个大于3的元素
    auto it = std::find_if(nums.begin(), nums.end(),
    [](int n) { return n > 3; });

    // 排序(降序)
    std::sort(nums.begin(), nums.end(),
    [](int a, int b) { return a > b; });
  • 事件处理:作为事件回调

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Button {
    public:
    using ClickHandler = std::function<void()>;
    void setOnClick(ClickHandler handler) {
    onClick = handler;
    }
    void click() {
    if (onClick) onClick();
    }
    private:
    ClickHandler onClick;
    };

三、智能指针:内存管理的革命

shared_ptr:共享所有权

基本语法

1
2
3
4
5
6
7
8
9
10
11
#include <memory>

// 创建shared_ptr
auto sp1 = std::make_shared<int>(42); // 推荐方式
std::shared_ptr<int> sp2(new int(100)); // 不推荐,可能导致内存泄漏

// 共享所有权
auto sp3 = sp1; // 引用计数变为2

// 检查引用计数
std::cout << sp1.use_count() << std::endl; // 2

使用场景

  • 多个所有者:当对象需要被多个所有者共享时
    1
    2
    3
    4
    class Node {
    public:
    std::vector<std::shared_ptr<Node>> children;
    };

unique_ptr:独占所有权

基本语法

1
2
3
4
5
6
// 创建unique_ptr
auto up1 = std::make_unique<int>(42); // C++14
std::unique_ptr<int> up2(new int(100)); // C++11

// 所有权转移
auto up3 = std::move(up1); // up1现在为空

使用场景

  • 独占资源:当对象只需要一个所有者时
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class FileHandler {
    public:
    FileHandler(const std::string& filename) {
    file_ = fopen(filename.c_str(), "r");
    }

    ~FileHandler() {
    if (file_) {
    fclose(file_);
    }
    }

    // 禁止复制
    FileHandler(const FileHandler&) = delete;
    FileHandler& operator=(const FileHandler&) = delete;

    private:
    FILE* file_;
    };

weak_ptr:打破循环引用

基本语法

1
2
3
4
5
6
7
8
9
10
11
12
// 从shared_ptr创建weak_ptr
auto sp = std::make_shared<int>(42);
std::weak_ptr<int> wp = sp;

// 检查是否过期
if (!wp.expired()) {
// 锁定获取shared_ptr
auto locked = wp.lock();
if (locked) {
std::cout << *locked << std::endl; // 42
}
}

使用场景

  • 观察者模式:观察者持有被观察者的弱引用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    class Subject {
    public:
    void attach(std::shared_ptr<Observer> observer) {
    observers_.push_back(observer);
    }

    void notify() {
    for (auto it = observers_.begin(); it != observers_.end();) {
    auto observer = it->lock();
    if (observer) {
    observer->update();
    ++it;
    } else {
    it = observers_.erase(it);
    }
    }
    }

    private:
    std::vector<std::weak_ptr<Observer>> observers_;
    };

四、移动语义:性能优化的利器

移动构造函数和移动赋值运算符

基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Buffer {
private:
char* data_;
size_t size_;

public:
// 构造函数
Buffer(size_t size) : size_(size) {
data_ = new char[size];
}

// 析构函数
~Buffer() {
if (data_) {
delete[] data_;
}
}

// 移动构造函数
Buffer(Buffer&& other) noexcept : data_(other.data_), size_(other.size_) {
other.data_ = nullptr;
other.size_ = 0;
}

// 移动赋值运算符
Buffer& operator=(Buffer&& other) noexcept {
if (this != &other) {
delete[] data_;
data_ = other.data_;
size_ = other.size_;
other.data_ = nullptr;
other.size_ = 0;
}
return *this;
}

// 禁用复制
Buffer(const Buffer&) = delete;
Buffer& operator=(const Buffer&) = delete;
};

使用场景

  • 避免不必要的复制:当对象包含大型资源时
    1
    2
    3
    Buffer createLargeBuffer() {
    return Buffer(1024 * 1024); // 移动语义避免复制
    }

std::move 和 std::forward

std::move

1
2
3
// 将左值转换为右值引用
std::string s = "Hello";
std::string s2 = std::move(s); // s现在为空

std::forward

1
2
3
4
5
// 完美转发
template<typename T>
void forwarder(T&& t) {
processor(std::forward<T>(t)); // 保持值类别
}

五、范围for循环:简洁的遍历

基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 遍历容器
std::vector<int> nums = {1, 2, 3, 4, 5};

// 基本用法
for (int n : nums) {
std::cout << n << " ";
}

// 使用引用(修改元素)
for (auto& n : nums) {
n *= 2;
}

// 遍历map
std::map<std::string, int> scores = {"Alice", 90, "Bob", 85};
for (const auto& [name, score] : scores) {
std::cout << name << ": " << score << std::endl;
}

使用场景

  • 简化遍历代码:替代传统的for循环
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 传统方式
    for (std::vector<int>::iterator it = nums.begin(); it != nums.end(); ++it) {
    std::cout << *it << " ";
    }

    // 范围for循环
    for (int n : nums) {
    std::cout << n << " ";
    }

六、其他重要特性

nullptr:空指针常量

1
2
3
4
5
// 传统的空指针
char* p = NULL; // 可能被定义为0

// C++11的nullptr
char* p = nullptr; // 类型安全的空指针

enum class:类型安全的枚举

1
2
3
4
5
6
7
8
9
10
11
// 传统枚举(可能导致命名冲突)
enum Color { RED, GREEN, BLUE };
enum Direction { LEFT, RIGHT, UP, DOWN };

// C++11枚举类
enum class Color { RED, GREEN, BLUE };
enum class Direction { LEFT, RIGHT, UP, DOWN };

// 使用
Color c = Color::RED;
Direction d = Direction::LEFT;

右值引用

1
2
3
4
5
6
7
// 左值引用
int x = 5;
int& lr = x; // 左值引用

// 右值引用
int&& rr = 5; // 右值引用
int&& rr2 = std::move(x); // 将左值转换为右值引用

default 和 delete 关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyClass {
public:
// 默认构造函数
MyClass() = default;

// 禁用复制构造
MyClass(const MyClass&) = delete;

// 禁用赋值运算符
MyClass& operator=(const MyClass&) = delete;

// 移动构造
MyClass(MyClass&&) = default;
};

委托构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Person {
public:
// 主构造函数
Person(std::string name, int age) : name_(std::move(name)), age_(age) {}

// 委托构造函数
Person(std::string name) : Person(std::move(name), 0) {}

Person() : Person("", 0) {}

private:
std::string name_;
int age_;
};

七、总结

C++11是现代C++的基础,引入了大量革命性的特性,包括:

核心特性

  1. auto 和 decltype:简化类型声明,提高代码可读性
  2. Lambda表达式:提供简洁的匿名函数,增强STL算法的使用
  3. 智能指针:自动化内存管理,减少内存泄漏
  4. 移动语义:提高性能,避免不必要的复制
  5. 范围for循环:简化容器遍历
  6. nullptr:类型安全的空指针
  7. enum class:类型安全的枚举
  8. 右值引用:支持移动语义
  9. default/delete:控制特殊成员函数
  10. 委托构造函数:减少代码重复

使用建议

  • 优先使用智能指针管理动态内存
  • 利用移动语义提高性能
  • 使用Lambda表达式简化回调和算法
  • 采用范围for循环提高代码可读性
  • 遵循现代C++的设计理念:类型安全、资源管理自动化、性能优化

C++11为C++注入了新的活力,使得代码更加安全、高效和可维护。掌握这些特性是成为现代C++程序员的必备技能。