之前寫了下面這樣的一段代碼(數據類型簡化了一下,功能類似),結果老是報錯誤 "iterator can not dereference" 或者是 "iterators incompatible"的運行時錯誤.後來找到了問題的關鍵是一個疏忽,但是又容易犯,這裏記錄下方便以後遇到類似的問題給自己提個醒。
#include <iostream>
#include <list>
using namespace std;
class MyList
{
public:
MyList(){}
void addElement(int e)
{
m_list.push_back(e);
}
list<int> getList()
{
return m_list;
}
private:
list<int> m_list;
};
int main()
{
MyList myList;
myList.addElement(1);
myList.addElement(2);
myList.addElement(3);
for (auto iter = myList.getList().cbegin();
iter != myList.getList().cend(); ++iter)
{
cout << *iter << " ";
}
return 0;
不知道大家有沒有人一眼就看出了問題,反正我是折騰了老半天才找出問題,還是自己編碼疏忽不嚴謹導致的。
上面的問題關鍵在於,調用了兩次 getList()並獲取其相應的迭代器進行了比較。由於getList()返回的是MyList類內部的一個std::list<int> 的副本,所以兩次調用返回的 std::list<int>是內容相同的兩個副本,他們的迭代器指向不同的迭代區間,STL定義了不同容器的迭代器是不能比較的,所以導致上面錯誤。可以通過下面這行代碼來驗證:
if (myList.getList().cbegin() != myList.getList().cend()){}
這段代碼僅僅只是比較一下兩個容器的迭代器,同樣引發程序運行時錯誤。
其實如果自己寫代碼時考慮周到一點就不會遇到這樣的低級錯誤了,下面是兩種改寫方法:
方法1:使用同一容器的迭代器比較
list<int> m_list = myList.getList();
for (auto iter = m_list.cbegin(); iter != m_list.cend(); ++iter)
{
cout << *iter << " ";
}
方法 2 : 修改 MyList::getList() 方法,使其返回引用類型,這樣多次調用返回的都是同一容器
list<int>& getList()
{
return m_list;
}