文章目錄
- 一、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