std::unique_ptr<int> p1 = std::make_unique<int>(5);
// std::unique_ptr p2 = p1; // 这会导致编译错误,因为unique_ptr不能被复制
std::unique_ptr<int> p2 = std::move(p1);
int* p3 = p2.release();
std::cout<<*p3<<std::endl;
**shared_ptr:**这个指针允许多个shared_ptr指向同一个对象,内部不仅包含了指向动态分配的内存的指针,还包含一个引用计数块,用于维持一个引用计数(当前有多少shared_ptr指向这个对象),当引用计数==0时,自动释放内存。
使用示例:
std::shared_ptr<int> p1 = std::make_shared<int>(5);
std::shared_ptr<int> p2 = p1;
std::cout << "引用计数: " << p1.use_count() << std::endl;
// 此时引用计数为2
{
std::shared_ptr<int> p3 = p1;
std::cout << "引用计数: " << p1.use_count() << std::endl;
// 此时引用计数为3,因为p3也指向同一块内存
}
std::cout << "引用计数: " << p1.use_count() << std::endl;
// 当p3超出作用域,引用计数变回2
return 0;
右值引用和move语句:
左值:有实际的内存地址的变量。
右值:无实际内存地址,临时量,语句结束后即消失。
左值可以作为右值参加运算,但是右值不可以作为左值。
int a = 5;
int b = a + 1;
左值引用:用一个&将另一个变量作为这个变量的别名,绑定后不能更换。
右值引用:用&&绑定一个右值,可以增加右值的生命周期,也只能绑定一个右值。
move函数:告诉编译器可以将一个左值看作右值引用,将左值的资源看作右值绑定在右值引用上,将资源的直接转移到新对象中而不是赋值(需要拷贝一份,浪费资源),move后的左值不可再使用。
lambda表达式
定义一个匿名函数,结构是[捕获列表](参数列表)->返回值类型 {函数体}
auto lambda = [](int x, int y) -> int { return x + y; }; int result = lambda(3, 4);
std::vector<int> numbers = {5, 2, 8, 1, 9};
// 使用lambda表达式定义升序排序规则,传递给std::sort函数
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a < b;
});
for (int num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
统一初始化方式
统一初始化主要使用花括号{}来初始化对象,这种方式可以用于初始化基本数据类型、数组、结构体、类对象以及容器等多种类型的对象。
//数组初始化
int arr[]{1, 2, 3, 4, 5};
//变量初始化
int a{5};
double b{3.14};
//类初始化
class MyClass {
public:
int value;
MyClass(int val) : value(val) {}
};
MyClass mc{42};
//序列式容器初始化
std::vector<int> v{1, 2, 3, 4, 5};
//关联式容器初始化
std::map<int, std::string> m{{1, "one"}, {2, "two"}};
内存构成分别是栈,堆,全局/静态数据区,常量区,代码段。
vector:可以扩展的数组,底层包含了一个数组和三个迭代器,分别指向数组头部start,数组最后一个元素的下一个地址capacity,和指向当前最后一个元素的后面的size。
当size==capacity时,vector会找一个2倍于当前内存空间的地址将原数组的值拷贝(有移动构造调用对象的移动构造函数)过去,在释放原来那块内存。
支持随机访问和指定位置插入:通过首地址和偏移量,就可以快速找到访问的地址。先插入到尾部,再和前面的值交换到指定位置。
list:由多个节点组成,节点之间的连接靠节点本身的两个指向前后节点的指针。
不支持随机访问,只能顺序访问,但是插入和删除的速度快。
deque:双端队列,中控区是一个指针数组,存放指向各个相等大小的缓冲区的指针,在缓冲区(连续地址空间)内存放数据,访问deque的迭代器中含有指向中控区的指针和指向缓冲区元素的指针。
索引/缓冲区个数就是位于第几个缓冲区,索引%缓冲区个数就是缓冲区内的偏移量。通过这种方式实现随机访问。插入操作时,迭代器找到插入的位置,然后将较少一边的元素后移。
map和set:底层用红黑树实现,有序的存放,按照key值从小到大存,查找和插入删除都是Ologn。存放的值是唯一的。multimap和multiset允许存放相同的key。
unordered_map和unordered_set:unordered_map和unordered_set的key值无序存储,底层使用哈希表存放,查找和插入删除是O1,不适合顺序遍历的场景。