38、Cpp11新特性介绍

厨子大约 4 分钟C++C++基础编程程序厨

C++11C++语言的一次重大更新,引入了许多新特性,极大地提升了代码的简洁性。

本文会详细介绍C++11中主要的几个新特性。

auto关键字与类型推导

auto关键字的作用

auto关键字用于自动推导变量的类型。编译器会根据变量的初始化表达式推断出变量的类型,简化我们的代码。

使用场景

  • 简化复杂类型的声明:例如迭代器、函数指针等。
  • 提高代码的可读性:减少冗余的类型声明。

代码示例

#include <iostream>
#include <vector>
using namespace std;

int main() {
    auto i = 10; // i的类型推导为int
    auto d = 3.14; // d的类型推导为double
    auto s = "Hello"; // s的类型推导为const char*

    vector<int> vec = {1, 2, 3, 4, 5};
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        cout << *it << " "; // 输出:1 2 3 4 5
    }
    cout << endl;

    return 0;
}

注意事项

  • auto不能用于函数参数类型推导。
  • auto推导的类型是值类型,如果需要引用类型,可以使用auto&

详见:auto&decltypeopen in new window

nullptr与智能指针

nullptr

nullptr是C++11引入的空指针常量,用于替代NULLnullptr的类型是std::nullptr_t,可以隐式转换为任何指针类型。

#include <iostream>
using namespace std;

void func(int* ptr) {
    if (ptr == nullptr) {
        cout << "Pointer is null." << endl;
    } else {
        cout << "Pointer is not null." << endl;
    }
}

int main() {
    int* p = nullptr;
    func(p); // 输出:Pointer is null.
    return 0;
}

详见:使用nullptr而非NULLopen in new window

智能指针

智能指针是C++11引入的一种管理动态内存的工具,可以自动释放内存,避免内存泄漏。

shared_ptr

shared_ptr是一种共享所有权的智能指针,通过引用计数管理内存。

#include <iostream>
#include <memory>
using namespace std;

class MyClass {
public:
    MyClass() { cout << "MyClass constructed." << endl; }
    ~MyClass() { cout << "MyClass destroyed." << endl; }
};

int main() {
    shared_ptr<MyClass> ptr1 = make_shared<MyClass>();
    {
        shared_ptr<MyClass> ptr2 = ptr1; // 引用计数增加
        cout << "Inside inner scope." << endl;
    } // ptr2离开作用域,引用计数减少
    cout << "Outside inner scope." << endl;
    return 0;
}

unique_ptr

unique_ptr是一种独占所有权的智能指针,不能复制,但可以移动。

#include <iostream>
#include <memory>
using namespace std;

class MyClass {
public:
    MyClass() { cout << "MyClass constructed." << endl; }
    ~MyClass() { cout << "MyClass destroyed." << endl; }
};

int main() {
    unique_ptr<MyClass> ptr1 = make_unique<MyClass>();
    // unique_ptr<MyClass> ptr2 = ptr1; // 错误:不能复制
    unique_ptr<MyClass> ptr2 = move(ptr1); // 可以移动
    return 0;
}

详见:智能指针open in new window

Lambda表达式与闭包

Lambda表达式

Lambda表达式是一种匿名函数,可以在需要函数对象的地方直接定义和使用。

语法如下:

[捕获列表](参数列表) -> 返回类型 { 函数体 }

捕获列表

捕获列表用于指定Lambda表达式可以访问的外部变量:

  • []:不捕获任何变量。
  • [&]:以引用方式捕获所有变量。
  • [=]:以值方式捕获所有变量。
  • [&x, y]:以引用方式捕获x,以值方式捕获y

代码示例

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> vec = {1, 2, 3, 4, 5};

    // 使用Lambda表达式作为谓词
    auto isEven = [](int x) { return x % 2 == 0; };
    auto it = find_if(vec.begin(), vec.end(), isEven);
    if (it != vec.end()) {
        cout << "First even number: " << *it << endl; // 输出:First even number: 2
    }

    // 使用Lambda表达式修改外部变量
    int sum = 0;
    for_each(vec.begin(), vec.end(), [&sum](int x) { sum += x; });
    cout << "Sum of vector: " << sum << endl; // 输出:Sum of vector: 15

    return 0;
}

闭包

闭包是指Lambda表达式与其捕获的外部变量组成的整体。闭包可以在函数调用结束后仍然保留捕获的变量状态。

范围for循环与decltype

范围for循环

通过范围for循环,可以简化遍历容器或数组的代码。

语法

for (元素类型 变量名 : 容器) {
    // 循环体
}

代码示例

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> vec = {1, 2, 3, 4, 5};

    // 使用范围for循环遍历vector
    for (int x : vec) {
        cout << x << " "; // 输出:1 2 3 4 5
    }
    cout << endl;

    return 0;
}

decltype关键字

decltype关键字用于推导表达式的类型。

使用场景

  • 推导复杂表达式的类型。
  • 它与auto结合使用,推导函数返回类型。

代码示例

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int x = 10;
    decltype(x) y = 20; // y的类型推导为int

    vector<int> vec = {1, 2, 3, 4, 5};
    decltype(vec.begin()) it = vec.begin(); // it的类型推导为vector<int>::iterator

    cout << "y = " << y << endl; // 输出:y = 20
    cout << "*it = " << *it << endl; // 输出:*it = 1

    return 0;
}

练习

  1. 使用auto关键字简化以下代码:

    1. std::vector<int>::iterator it = vec.begin();
      
  2. 使用shared_ptrunique_ptr分别实现一个简单的资源管理类。

  3. 使用Lambda表达式实现一个通用的排序函数,支持对任意类型的容器进行排序。

  4. 使用范围for循环遍历一个std::map,并输出键值对。