C++11引入了众多新特性,以下是一些比较常用且重要的新特性介绍:
1. 语言核心特性增强
- 自动类型推断(
auto关键字):
编译器可以根据变量的初始值自动推断其类型,简化了复杂类型变量的声明,尤其适用于迭代器、lambda表达式等返回复杂类型的情况。例如:
auto i = 5; // i被推断为int类型
auto it = std::vector<int>{1, 2, 3}.begin(); // it被推断为std::vector<int>::iterator类型
- 范围
for循环:
能够简洁地遍历容器或可迭代对象,让代码更易读、易写。语法形式如下:
std::vector<int> vec = {1, 2, 3};
for (auto element : vec) {
std::cout << element << " ";
}
// 输出: 1 2 3
nullptr关键字:
用于表示空指针,替代原来容易产生歧义的NULL(在C++中NULL实际是int类型的宏定义,而nullptr是专门的指针类型常量),增强了代码的类型安全性。例如:
int* ptr = nullptr;
2. 初始化列表(std::initializer_list)
允许使用花括号{}来初始化对象,支持对自定义类型、容器等进行初始化,方便且直观。例如:
std::vector<int> v = {1, 2, 3};
struct Point {
int x;
int y;
};
Point p = {10, 20};
同时,函数也可以接受初始化列表作为参数,比如:
void printElements(std::initializer_list<int> list) {
for (auto element : list) {
std::cout << element << " ";
}
std::cout << std::endl;
}
printElements({1, 2, 3});
3. Lambda表达式
可以在代码中创建匿名函数,方便在需要函数对象的地方(如std::sort算法的比较函数、std::for_each的操作函数等)快速定义简单的函数逻辑。语法形式一般为:
[捕获列表](参数列表) -> 返回类型 {函数体}
例如,对一个vector进行排序,使用lambda表达式定义比较函数:
std::vector<int> numbers = {5, 3, 1, 4, 2};
std::sort(numbers.begin(), numbers.end(), [](int a, int b) -> bool { return a < b; });
捕获列表可以捕获外部变量供lambda函数内部使用,如按值捕获、按引用捕获等,示例如下:
int factor = 2;
std::vector<int> nums = {1, 2, 3};
std::for_each(nums.begin(), nums.end(), [factor](int& num) { num *= factor; });
4. 右值引用与移动语义
- 右值引用(
&&):
是一种新的引用类型,用于绑定到右值(临时对象、表达式返回值等),与传统左值引用区分开,开启了移动语义等优化操作的可能性。例如:
int&& rvalueRef = 10; // 绑定到右值(字面量常量)
- 移动语义:
通过定义移动构造函数(如ClassName(ClassName&& other))和移动赋值运算符(如ClassName& operator=(ClassName&& other)),实现将临时对象(右值)的资源高效地“移动”给另一个对象,避免了传统拷贝语义下的资源深拷贝,提升性能。例如:
class MyString {
private:
char* data;
size_t length;
public:
// 移动构造函数示例
MyString(MyString&& other) : data(other.data), length(other.length) {
other.data = nullptr;
other.length = 0;
}
// 省略其他成员函数
};
5. 新的容器和容器相关特性
std::array:
是一个固定大小的数组容器,它结合了普通数组的性能优势和容器类的一些方便特性(如begin、end迭代器方法等),在编译期确定大小,更安全、易用。例如:
std::array<int, 5> arr = {1, 2, 3, 4, 5};
std::forward_list:
是一个单向链表容器,适合一些只需单向遍历、对插入删除操作效率有要求的场景,相比于std::list(双向链表)在空间上可能更节省,操作开销也有不同特点。例如:
std::forward_list<int> flist;
flist.push_front(1);
flist.push_front(2);
std::unordered_map和std::unordered_set:
基于哈希表实现,相比于传统的std::map(红黑树实现)和std::set,在查找、插入、删除操作上平均时间复杂度更低(接近常数时间),适用于对查找性能要求较高、不要求元素有序的场景。例如:
std::unordered_map<std::string, int> umap;
umap["apple"] = 5;
umap["banana"] = 3;
6. 多线程支持(std::thread、std::mutex等)
std::thread:
用于创建和管理线程,使得在C++中编写多线程程序更加方便、直观。例如:
#include <iostream>
#include <thread>
void hello() {
std::cout << "Hello from thread " << std::this_thread::get_id() << std::endl;
}
int main() {
std::thread t(hello);
std::cout << "Hello from main thread " << std::this_thread::get_id() << std::endl;
t.join();
return 0;
}
std::mutex(互斥锁)及其相关类型(std::lock_guard等):
用于保护共享资源,防止多个线程同时访问导致数据不一致等问题。std::lock_guard是一种方便的RAII(Resource Acquisition Is Initialization)机制的锁管理类,能自动在构造函数中锁定互斥锁,在析构函数中解锁,避免了手动管理锁的释放问题。例如:
std::mutex mutex;
int sharedData = 0;
void increment() {
std::lock_guard<std::mutex> guard(mutex);
sharedData++;
}
7. 类型别名(using关键字)
使用using关键字可以为已有类型定义别名,相比typedef,它的语法更加直观、灵活,特别是在定义模板别名等复杂情况时优势明显。例如:
using IntVector = std::vector<int>;
IntVector v = {1, 2, 3};
// 定义函数指针类型别名示例
using FuncPtr = void (*)(int);
8. 委托构造函数(Delegating Constructors)
允许在一个构造函数中调用同一个类的其他构造函数,减少代码重复,方便初始化逻辑的复用。例如:
class Point {
public:
Point(int xVal, int yVal) : x(xVal), y(yVal) {}
Point() : Point(0, 0) {} // 委托构造函数,调用有参数的构造函数进行初始化
private:
int x;
int y;
};
9. 显式虚函数重载(override关键字)
在派生类中重写基类的虚函数时,可以使用override关键字来显式表明这是一个重写操作。这样编译器能帮我们检查是否正确重写了虚函数(比如函数签名是否一致等),避免一些因重写错误导致的运行时问题。例如:
class Base {
public:
virtual void func() {}
};
class Derived : public Base {
public:
void func() override { // 使用override关键字
// 具体实现
}
};
10. 常量表达式(constexpr)
可以让函数或对象在编译期求值,扩大了编译期计算的范围,常用于定义编译期就能确定值的常量、数组大小等,提升程序性能和可预测性。例如:
constexpr int factorial(int n) {
return (n <= 1)? 1 : n * factorial(n - 1);
}
constexpr int result = factorial(5); // 在编译期计算阶乘结果
这些只是C++11众多新特性中的一部分,它们为C++编程带来了更多便利、高效以及功能上的拓展,让开发者可以写出更现代、更强大的C++代码。

1360

被折叠的 条评论
为什么被折叠?



