C++11 新特性
核心语言特性
1. 自动类型推导 (auto
)
- 当我们写错了一个变量的类型,例如:
int a = "abc";
。编译器可以在编译期间,就明确当前代码有误。 - 既然编译器明确的知道,等号右边的类型是什么,那么就不要劳烦开发者自己操心应该用什么类型了。
cpp
auto i = 5; // int
auto str = "hello"; // const char*
2. 基于范围的 for 循环
- 简化容器遍历,代码更简洁易读。
cpp
std::vector<int> vec{1,2,3};
for (auto& num : vec) { /* 操作每个元素 */ }
3. Lambda 表达式
- 开发者经常为编写一个合适的函数名,感到头疼。很多函数只使用一次,一个漂亮又贴切的命名,其实并没有那么重要。
- 那么就不要再劳心劳力的为这种一次性函数起名字了。
cpp
auto sum = [](int a, int b) { return a + b; };
std::vector<int> vec{3, 1, 4, 1, 5};
std::sort(vec.begin(), vec.end(), [](int a, int b){ return a > b; });
4. 右值引用,移动语义,完美转发 (&&
, std::move
, std::forward
)
- 非常重要,可以显著提高代码在对象拷贝时的性能。
- 但是语法比较违反直觉,必须跳出常规编程的一些思维模式。
- 在函数参数和返回值中,移动语义会真正体现出优势。
cpp
std::string s1 = "Hello";
std::string s2 = std::move(s1); // s1 资源转移给 s2
std::cout << s2 << std::endl; // 输出 "Hello"
std::cout << s1 << std::endl; // 输出空字符串,s1 已失效
5. nullptr
关键字
- NULL是通过宏定义实现的0,存在类型安全问题
nullptr
是类型安全的空指针替代NULL
nullptr
相比 NULL
的优势:
5.1 类型安全
cpp
void func(int x) { std::cout << "int: " << x << std::endl; }
void func(char* ptr) { std::cout << "char*: " << ptr << std::endl; }
// 使用 NULL 会产生歧义
func(NULL); // 可能调用 func(int),因为 NULL 是 0
func(nullptr); // 明确调用 func(char*),类型安全
5.2 模板中的类型推导
cpp
template<typename T>
void process(T* ptr) {
if (ptr != nullptr) { // 清晰明确
// 处理指针
}
}
// NULL 在模板中可能被推导为 int 类型
// nullptr 始终是指针类型
5.3 避免整数与指针混淆
cpp
int* ptr1 = NULL; // NULL 本质是 0
int* ptr2 = nullptr; // nullptr 是真正的空指针常量
if (ptr1 == 0) { } // 可以编译,但语义不清
if (ptr2 == nullptr) { } // 语义明确
5.4 更好的代码可读性
cpp
int* ptr = nullptr; // 一眼就知道这是空指针
6. 强类型枚举 (enum class
)
- 避免命名冲突,禁止隐式转换
- 提供作用域限定,避免全局命名空间污染
cpp
enum class Color { Red, Green, Blue };
Color c = Color::Red;
// int x = Color::Red; // 编译错误,禁止隐式转换
7. 常量表达式 (constexpr
)
- 编译时计算,提升运行时性能
cpp
constexpr int square(int x) { return x * x; }
int arr[square(5)]; // 编译时确定数组大小
8. 委托构造函数
- 构造函数调用同类其他构造函数,避免重复代码
cpp
class MyClass {
public:
MyClass(int a) : x(a) {}
MyClass() : MyClass(0) {} // 委托
};
9. override
和 final
关键字
- 明确虚函数覆盖/禁止覆盖
- 在代码维护时,可以确保多态能够正常工作。
- 如果不小心修改了基类或者派生类的签名,编译器可以通过明确的报错,确保不会出现多态变成同名覆盖。
cpp
class Base {
virtual void foo() {} // 可以被覆盖
virtual void bar() final; // 禁止派生类覆盖
};
class Derived : public Base {
void foo() override; // 显式声明覆盖
// void bar() override; // 编译错误,final禁止覆盖
};
10. 变长模板 (Variadic Templates)
- 支持任意数量模板参数
cpp
template<typename... Args>
void print(Args... args) { /* 递归展开 */ }
11. 统一初始化语法(大括号初始化)
- 提供统一的初始化语法,适用于所有类型
- 防止窄化转换,提高类型安全
cpp
int x{5}; // 基本类型
std::vector<int> v{1, 2, 3}; // 容器
struct Point { int x, y; };
Point p{10, 20}; // 聚合类型
12. decltype
关键字
- 推导表达式的类型,常用于模板编程
cpp
int x = 5;
decltype(x) y = 10; // y 的类型是 int
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
return t + u;
}
13. 默认和删除函数
- 显式控制编译器生成的特殊成员函数
cpp
class MyClass {
public:
MyClass() = default; // 使用默认构造函数
MyClass(const MyClass&) = delete; // 禁止拷贝构造
MyClass& operator=(const MyClass&) = delete; // 禁止拷贝赋值
};
标准库增强
1. 智能指针
-
这里涉及到一个RAII的概念,通过避免使用裸指针的方式,实现自动内存管理。
-
std::unique_ptr
:独占所有权,禁止拷贝和赋值 -
std::shared_ptr
:强引用,共享所有权,通过引用计数的方式,实现内存自动管理(引用计数为0时,释放对象) -
std::weak_ptr
:弱引用,避免循环引用,不会增加引用计数,不能直接访问对象
cpp
auto ptr = std::make_unique<int>(10);
auto strong = std::make_shared<int>(10);
auto weak = std::weak_ptr<int>(strong);
2. 容器改进
- 初始化列表:
std::vector<int> v = {1, 2, 3};
- 新增容器:
std::array
:固定大小数组std::forward_list
:单向链表std::unordered_set/map
:哈希容器
3. 正则表达式 (<regex>
)
cpp
std::regex pattern("\\d+");
bool match = std::regex_search("123abc", pattern);
4. 多线程支持 (<thread>
, <mutex>
, <future>
)
- future是一个非常重要的关键字,后续会单独进行详细说明
cpp
std::thread t([](){ std::cout << "Hello Thread!"; });
t.join();
5. 时间库 (<chrono>
)
cpp
auto start = std::chrono::steady_clock::now();
// ... 执行代码
auto dur = std::chrono::steady_clock::now() - start;
6. 元组 (std::tuple
)
- 允许将多个对象组合成一个对象,并访问组合对象中的元素
- 之前可能需要返回一个自定义结构体的情况,现在可以直接使用元组
- 之前函数返回值只能返回一个值,现在可以通过返回元组,实现返回多个值
cpp
std::tuple<int, std::string> tup(1, "text");
auto val = std::get<1>(tup); // "text"
其他重要特性
1. 类型别名 (using
替代 typedef
)
cpp
template<typename T>
using Vec = std::vector<T>; // 模板别名
2. 静态断言 (static_assert
)
cpp
static_assert(sizeof(int) == 4, "32-bit required");
3. 属性语法 ([[attributes]]
)
cpp
[[deprecated("Use new_func()")]] void old_func();
4. 原始字符串字面量
- 避免转义字符的复杂性,特别适用于正则表达式和文件路径
cpp
std::string path = R"(C:\Users\Name\Documents)";
std::string regex = R"(\d{4}-\d{2}-\d{2})";
5. 线程局部存储 (thread_local
)
- 每个线程都有自己的变量副本
cpp
thread_local int counter = 0; // 每个线程独立的计数器
完整示例(综合使用)
cpp
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
#include <thread>
#include <future>
class Calculator {
public:
Calculator() = default;
Calculator(const Calculator&) = delete;
Calculator& operator=(const Calculator&) = delete;
template<typename... Args>
auto sum(Args... args) -> decltype((args + ...)) {
return (args + ...);
}
};
int main() {
// 统一初始化 + auto
auto nums = {1, 2, 3, 4, 5};
// 智能指针 + 基于范围的循环
std::vector<std::unique_ptr<int>> ptrs;
for (auto&& num : nums) {
ptrs.emplace_back(std::make_unique<int>(num));
}
// Lambda 表达式 + 移动语义
auto print = [vec = std::move(ptrs)]() {
for (const auto& p : vec) {
std::cout << *p << " ";
}
std::cout << std::endl;
};
// 异步执行
auto future = std::async(std::launch::async, print);
future.wait();
// 强类型枚举
enum class Status { Ready, Running, Done };
Status status = Status::Done;
// constexpr 函数
constexpr auto square = [](int x) constexpr { return x * x; };
static_assert(square(5) == 25, "Compile-time calculation");
return 0;
}
这些特性显著提升了 C++ 的表达能力、安全性和性能,奠定了现代 C++ 开发的基础。后续标准(C++14/17/20)在此基础上进行了扩展和完善。