C++11新特性
lamda表达式
Lambda表达式是一种在被调用的位置或作为参数传递给函数的位置定义匿名函数对象(闭包)的简便方法。本质还是匿名对象。注意这是一个表达式要加入;
const auto fun = [capture list] (parameter list) -> return type { function body };
capture list
是捕获列表,用于指定 Lambda表达式可以访问的外部变量,以及是按值还是按引用按引用的方式访问。捕获列表可以为空,表示不访问任何外部变量,也可以使用默认捕获模式 & 或 = 来表示按引用或按值捕获所有外部变量,还可以混合使用具体的变量名和默认捕获模式来指定不同的捕获方式。可以是具体变量名和表达式。c++ 17支持this指针的捕获。
parameter list
是参数列表,用于表示 Lambda表达式的参数,可以为空,表示没有参数,也可以和普通函数一样指定参数的类型和名称,还可以在 c++14 中使用 auto 关键字来实现泛型参数。
return type
是返回值类型,用于指定 Lambda表达式的返回值类型,可以省略,表示由编译器根据函数体推导,也可以使用 -> 符号显式指定,还可以在 c++14 中使用 auto 关键字来实现泛型返回值。
function body
是函数体,用于表示 Lambda表达式的具体逻辑,可以是一条语句,也可以是多条语句,还可以在 c++14 中使用 constexpr 来实现编译期计算。
auto 类型推导
auto关键字支持类型的推到。在多个模板类型指定时可以使用,大大简便了书写,但是需要注意项目构建中类型命名的规范。通常是用来作为迭代器和函数类型的标识符。
foreach
v是任何的可迭代容器
for (auto& i : v) {
}
智能指针
RAII机制
1. std::unique_ptr
std::unique_ptr
是C++11引入的一种智能指针,它拥有其所指向的对象。这意味着 std::unique_ptr
的实例对其管理的资源拥有唯一所有权,不能复制(copy),但可以移动(move)。这使得它在需要唯一所有权语义的场景中非常有用。
#include <memory>
int main() {
std::unique_ptr<int> ptr = std::make_unique<int>(10);
// ptr.reset(); // 手动释放内存
// std::unique_ptr<int> ptr2 = ptr; // 错误,不能复制
std::unique_ptr<int> ptr2 = std::move(ptr); // 正确,通过移动语义
// 此时ptr变为nullptr
}
2. std::shared_ptr
std::shared_ptr
是另一种智能指针,它允许多个 shared_ptr
实例共享对同一个对象的所有权。当最后一个拥有该对象的 shared_ptr
被销毁或被重置时,该对象才会被删除。std::shared_ptr
通过控制块(control block)来管理所有权,控制块中包含了一个指向对象的指针和一个计数器,该计数器记录了有多少个 shared_ptr
实例指向该对象。
#include <memory>
int main() {
std::shared_ptr<int> ptr1 = std::make_shared<int>(10);
std::shared_ptr<int> ptr2 = ptr1; // 正确,ptr1和ptr2共享所有权
// 当ptr1和ptr2超出作用域时,所指向的int对象将被自动删除
}
3. std::weak_ptr
std::weak_ptr
是用来解决 std::shared_ptr
之间可能产生的循环引用问题的一种智能指针。std::weak_ptr
不拥有其所管理的对象,因此不会导致对象的生命周期延长。它更像是一个对 std::shared_ptr
所管理对象的非拥有性引用。
#include <memory>
class A;
class B;
class A {
public:
std::shared_ptr<B> bPtr;
// ...
};
class B {
public:
std::weak_ptr<A> aPtr; // 使用weak_ptr避免循环引用
// ...
};
int main() {
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->bPtr = b;
b->aPtr = a;
// 没有循环引用问题,因为b->aPtr是weak_ptr
}
初始化列表
{}
委托构造
委托构造允许一个构造函数调用另一个构造函数来完成初始化工作。
class Person {
public:
// 主构造函数,接受姓名和年龄
Person(const std::string& name, int age) : name(name), age(age) {
std::cout << "Main constructor called." << std::endl;
}
// 委托构造函数,只接受姓名
Person(const std::string& name) : Person(name, 20) { // 调用主构造函数
std::cout << "Delegating constructor called." << std::endl;
}
}
移动语义
移动语义指的是在移动对象时,对象本身无需复制,而是将所有权从一个对象转移到另一个对象。
左值:具有持久存储地址的表达式,可以在赋值操作中出现在等号的左边。左值引用int a = 10; int& b=a
右值:临时对象或值(将亡值),不能出现在赋值操作的左边。右值引用int&& a = 10;