文章目录
- 一、std::list不会产生引用失效问题
- 二、std::vector中元素引用失效问题
- 三、std::deque中元素引用失效问题
一、std::list不会产生引用失效问题
在C++中,std::list(双向链表)提供了一种非常灵活的容器类型,其设计使其在插入和删除元素时不会使其他元素的引用或指针失效。
这是因为std::list在内部使用节点来存储元素,每个节点都包含指向前后节点的指针,因此插入和删除操作只会影响相邻节点的指针,而不会影响其他节点。
std::list的引用和指针有效性:
- 插入元素:插入元素时,只需要调整相邻节点的指针,而不会重新分配或移动其他节点。因此,现有元素的引用和指针不会失效。
- 删除元素:删除元素时,只需要调整相邻节点的指针,然后删除节点本身。其他节点的引用和指针仍然有效。
eg:在std::list中插入和删除元素后,现有元素的引用和指针仍然有效:
#include <iostream>
#include <list>int main() {std::list<int> myList = {1, 2, 3, 4};// 获取指向第二个元素的引用和指针auto it = myList.begin();++it; // it指向第二个元素(2)int& ref = *it;std::cout << "Value of ref before insertions: " << ref << std::endl; // 输出2// 在列表中插入和删除元素myList.insert(it, 10); // 在第二个元素之前插入10myList.push_back(5); // 在末尾插入5std::cout << "Value of ref after insertions: " << ref << std::endl; // 输出2myList.erase(it); // 删除第二个元素(2)std::cout << "List after deletions: ";for (const auto& value : myList) {std::cout << value << " ";}std::cout << std::endl;return 0;
}
测试:
Program returned: 0
Program stdout
Value of ref before insertions: 2
Value of ref after insertions: 2
List after deletions: 1 10 3 4 5
在这个示例中,即使在列表中插入和删除元素后,ref(原本指向第二个元素的引用)仍然有效,并且保持其值为2。
使用智能指针避免同样会导致引用失效问题
- 使用智能指针(如std::shared_ptr和std::unique_ptr)可以显著减少引用失效问题,因为智能指针管理的是指向堆上对象的指针,而不是对象本身。
#include <iostream>
#include <memory>
#include <vector>int main() {std::vector<std::shared_ptr<int>> vec = {std::make_shared<int>(1),std::make_shared<int>(2),std::make_shared<int>(3)};std::shared_ptr<int>& ref = vec[1]; // 引用第二个元素std::cout << *ref << std::endl; // ref仍然有效,输出2vec.insert(vec.begin(), std::make_shared<int>(0)); // 在开头插入一个元素std::cout << *ref << std::endl; return 0;
}
编译:
Program returned: 139
Program stdout
2
Program stderr
Program terminated with signal: SIGSEGV
二、std::vector中元素引用失效问题
std::vector在以下情况下可能导致引用失效:
- 重新分配内存:当vector的容量不够时,会重新分配内存,将现有元素移动到新的内存位置。
- 插入和删除:在中间插入或删除元素时,后续元素会被移动,从而使指向这些元素的引用失效。
避免引用失效的方法:
- 预先分配足够的空间:使用reserve方法预先分配足够的空间,以减少重新分配内存的次数。
std::vector<int> vec;
vec.reserve(100); // 预先分配足够的空间
- 避免中间插入和删除:尽量减少在中间插入和删除元素的操作,可以选择在尾部插入或删除。
三、std::deque中元素引用失效问题
std::deque的设计使其在头尾插入和删除操作中引用失效的可能性较低,但在中间插入和删除时仍然可能导致引用失效。
避免引用失效的方法:
- 避免中间插入和删除:和vector类似,尽量减少在中间插入和删除元素的操作。
- 使用迭代器:在插入或删除元素后,重新获取迭代器。
使用智能指针避免同样会导致引用失效问题
- 在队列中间插入新的元素之后,旧的元素的值不正确
#include <deque>
#include <iostream>
#include <memory>
#include <vector>int main() {std::deque<std::shared_ptr<int>> deq = {std::make_shared<int>(1),std::make_shared<int>(2),std::make_shared<int>(3)};std::shared_ptr<int>& ref = deq[1]; // 引用第二个元素std::cout << *ref << std::endl; // ref仍然有效,输出2deq.insert(deq.begin() + 1,std::make_shared<int>(10)); // 在第二个位置插入元素std::cout << *ref << std::endl; // ref仍然有效, 但是输出10return 0;
}
编译:
Program returned: 0
Program stdout
2
10