目录
QString篇
//初始化
bool bOk = false;
QString str = "sd";
QString strTemp(str);
str = QString("%1,%2").arg("11").arg("-gg");
qDebug()<<str;
str.sprintf("%s %d","ni",1);
qDebug()<<str;
qDebug()<<str.toStdWString().data();
qDebug()<< str.sprintf(("%.3f"),3.1415926);
//需要注意 C asprintf是内存分配,失败返回-1好像,但是要free
qDebug()<< str.asprintf(("%2f"),3.1415926); //不建议使用官方说的
//is null "\0"不为空
str = "\0";
bOk = str.isEmpty();
qDebug()<<bOk;
bOk = str.isNull();
qDebug()<<bOk;
// 添加 也可以用运算符+
str = "sd";
str.append("89");
qDebug()<< str;
str.push_back("11");
str.push_front("A");
qDebug()<<str;
//移除
str.remove("sd");
qDebug()<<str;
//附加
str.prepend("-->");
qDebug()<<str;
// 计算长度
str = "sd\n";
qDebug()<<str.count();
qDebug()<<str.size();
qDebug()<<str.length();
QString* pStr = &str;
qDebug()<<pStr->count();
qDebug()<<pStr->size();
qDebug()<<pStr->length();
// 去空格
str = " 1 sd\n ";
qDebug()<< str.trimmed(); //去首
qDebug()<< str.simplified(); //首尾
//截取
str = "12345678";
qDebug()<< str.left(3);
qDebug()<< str.right(3);
qDebug()<< str.mid(2,5);
qDebug()<< str.remove(2,5);
// 有规律截取
QString csv = "forename,middlename,surname,phone";
QString path = "/usr/local/bin/myapp"; // First field is empty
QString::SectionFlag flag = QString::SectionSkipEmpty;
QString data = "forename**middlename**surname**phone";
str = data.section("**", 2, 2); // str == "surname"
str = data.section("**", -3, -2); // str == "middlename**surname"
str = csv.section(',', 2, 2); // str == "surname"
str = path.section('/', 3, 4); // str == "bin/myapp"
str = path.section('/', 3, 3, flag); // str == "myapp"
//切割字符
str = "q/w/e/r/t/y/u";
qDebug()<< str.split('/');
//超出用其他代替
str = "qwertyu";
qDebug()<< str.leftJustified(20,'.',true).toStdString().data();
//查询包含特定字符包含大小写(参数2区分大小写)
bOk = str.contains("llo Wor",Qt::CaseSensitive);
qDebug()<< bOk;
//以某个字符开头
bOk = str.startsWith("llo Wor",Qt::CaseInsensitive);
qDebug()<< bOk;
//以某个字符结尾
bOk = str.endsWith("llo Wor",Qt::CaseSensitive);
qDebug()<< bOk;
//替换字符
str.replace("l","2");
qDebug()<< str;
// 与QByteArray 相互转换
//我们都是在使用QString。QString存储了16位unicode码,很容易用来存储非ASCII或是非Lantin1的编码,另外QString在所有的QtAPI中都是通用的。
//有两种情况下会比较适合使用QByteArray,第一就是你要存储一般的位数据,第二种情况就是在内存资源很珍贵的情况下,例如像Qt for EmbeddedLinux
QByteArray byteArray = "Hello World";
str = QString::fromUtf8(byteArray);
str = "Hello World";
byteArray = str.toUtf8();
//转换进制
str = "-120";
int dec = str.toInt(&bOk);
qDebug()<< dec << bOk;
dec = str.toUInt(&bOk,16);
qDebug()<< dec << bOk;
str = "-120.5";
double db = str.toDouble();
qDebug()<< db;
float f = str.toFloat();
qDebug()<< f;
QByteArray 篇
提供字节数组。QByteArray 可用于存储原始字节(包括“0”)和传统的 8 位“0”终止字符串。使用 QByteArray 比使用 const char * 方便得多。在后台,它始终确保数据后面跟着“0”终止符,并使用隐式共享(写入时复制)来减少内存使用量并避免不必要的数据复制。同时QByteArray也支持容器操作append、prepend、remove、contains等操作
//初始化 QByteArray 的一种方法是简单地将 const char * 传递给其构造函数。
//例如,以下代码创建一个大小为 5 的字节数组,其中包含数据“Hello”:
QByteArray ba("hello");
// or 用下表赋值
ba.resize(5);
ba[0] = 0x3c;
ba[1] = 0xb8;
ba[2] = 0x64;
ba[3] = 0x18;
ba[4] = 0xca;
// 需要注意判断空,因为isNull指向空字节数组"0"字符(不是空指针)
QByteArray("").isNull(); // returns false
QByteArray("").isEmpty(); // returns true
//也支持 append/clear/compare/indexOf/insert/push_back/count/chop等操作,这里不一一介绍可以查看帮助文档
QByteArray x("free");
QByteArray y("dom");
x.append(y);
// x == "freedom"
//back()操作 等同于at(size() - 1)
qDebug()<<x.back();
//转char*
QByteArray array("Hello world");
char *data = array.data();
while (*data) {
qDebug() << "[" << *data << "]";
++data;
}
// or
QString tmp = "test";
QByteArray text = tmp.toLocal8Bit();
char *pdata = new char[text.size() + 1];
strcpy(pdata, text.data());
delete [] pdata;
// or
const char* pTemp = text.constData();
qDebug() << pTemp;
//转QByteArray
QString strTemp = QString(pTemp);
qDebug() << strTemp;
// 参数2故意写错 返回 "test\x00" 5
QByteArray byte(QByteArray::fromRawData(pTemp,5));
qDebug() << byte << byte.size();
byte = QByteArray(pTemp);
qDebug() << byte << byte.size();
// 进制转换
int n = 63;
qDebug() << QByteArray::number(n); // returns "63"
qDebug() << QByteArray::number(n, 16); // returns "3f"
qDebug() << QByteArray::number(n, 16).toUpper(); // returns "3F"
//unsigned char转换
char test[10240] = "hello Wold";
unsigned char test2[1024] = "123456";
QByteArray array1(test);
QByteArray array2 = QByteArray::fromRawData(reinterpret_cast<const char*>(test2), sizeof(test2));
QByteArray array3 = QString::fromUtf8(reinterpret_cast<const char*>(test2)).toUtf8();
看完上面来看看这个避坑实例
QByteArray byte;
byte[0] = 'A';
byte[1] = '\0';
byte[2] = '\0';
byte[3] = '\0';
QString strName = QString("%1%2%3%4").arg(byte[0]).arg(byte[1]).arg(byte[2]).arg(byte[3]);
QString nam = strName + "1";
qDebug()<< nam; //输出"A\u0000\u0000\u00001" 有的编译器调式输出A
nam = QString::fromUtf8(byte) + "1";
qDebug()<< nam; //输出"A1"
问题的原因在于
QString
的构造和显示方式。在代码中,
byte[0] = 'A'
将字符’A’的ASCII码值65存储在
byte[0]
中。然后,通过
arg
方法将
byte
的每个元素转换为
QString
并合并在一起,得到
strName
的值”A”。接下来,将字符串”A”与字符串”1″拼接,得到新的字符串”A1″,并存储在
nam
中。最后,使用
qDebug()
输出
nam
的值。在输出时,由于
QString
默认使用UTF-16编码,所以字符’A’的UTF-16编码的高字节部分为65,低字节部分为0,而字符’1’的UTF-16编码的高字节部分为49,低字节部分也为0。因此,当
qDebug()
输出
nam
时,它实际上输出了四个字符的UTF-16编码的高字节部分,即65、0、0、0和49
顺序容器
关于容器,首先要提一下模板template <typename T>,因为容器的实现方式就有模板这个概念。
关于容器储存数据要求:
1.须有构造函数(无参)
2.须有拷贝构造函数
3.赋值运算
需要注意:
QObject及其子类(如QWidget和Qdialog等)是不可以存储在容器中的,但QObject及其子类的指针可以存储在容器中。
因为它们不支持拷贝构造函数和赋值运算符。QObject及其子类采用了对象树的概念,它们之间存在所有权关系。当一个QObject对象被销毁时,它会自动销毁其所有的子对象。然而,QObject及其子类的指针可以存储在容器中,因为指针只是存储了对象的地址,并没有涉及对象本身的复制。容器内的指针使用完要手动释放
QList
QList内存方式使用连续的内存块来存储其元素,这些元素按照它们在列表中的顺序依次排列。当添加新的元素时,QList会根据需要自动扩展内存空间,以容纳更多的元素。如果列表中的元素被移除,QList会自动收缩内存空间(这里引出一个概念动态内容分配),同时也支持快速的随机访问,QList基于指针数组实现。即QList内部维护着一个指针数组,每个指针指向实际存储的元素。这样可以通过索引快速访问特定位置的元素。
QList<int> list;
//添加元素
list.append(1);
list.append(2);
list.push_front(-2);
list.push_back(3);
qDebug()<< list;
list.insert(0,-1);
list.insert(1,-1);
list.insert(2,-1);
qDebug()<< list; // (-2, -1, 1, 2, 3)
//删除 并释放内存控件 包含clear
list.removeAll(1);
qDebug()<< list;
list.removeOne(-1);
qDebug()<< list;
//并不释放内存控件
list.removeAt(0);
qDebug()<< list; // (-1, 1, 2, 3)
list.removeFirst();
qDebug()<< list;
list.removeLast();
qDebug()<< list;
list.pop_front();
qDebug()<< list;
list.pop_back();
qDebug()<< list;
list.clear();
qDebug()<< list;
//大小
list.append(1);
list.append(2);
int lenght = list.size(); // or lenght() or count
//访问
qDebug()<< list.at(0); // 效率高,不能当左值,但是序号不对容易崩溃
qDebug()<< list[0];
qDebug()<< list.value(1);
qDebug()<< list.value(3,-1); // 越界就返回设置值
//遍历 这里不要remove 当你删除一个元素后,迭代器会失效
// 遍历列表并删除某些元素
for(auto it = list.begin(); it != list.end();)
{
if(*it == 0)
{
// 删除当前元素并得到指向下一个元素的新迭代器
it = list.erase(it);
}
else
{
// 继续遍历下一个元素
++it;
}
}
// 遍历列表并在某些位置插入新元素
for(auto it = list.begin(); it != list.end(); ++it)
{
if(*it == 5)
{
// 在当前位置插入新元素,并得到指向新插入元素的迭代器
it = list.insert(it, 10);
// 更新迭代器以指向正确位置
++it;
}
}
//遍历 C++里的
for each (auto var in list)
{
qDebug()<< var;
}
QLinkedList
是双向链表,每个节点都存储了数据元素和指向下一个节点的指针。内存结构如下:首先,存储了指向第一个节点的指针(头指针)。每个节点包含两个主要部分:数据元素和指针。数据元素是节点中实际存储的数据,可以是任意类型。指针是指向下一个节点的指针,它存储了下一个节点的地址或空指针。因此重复删除或者移动速度会比Qlist快点
QLinkedList<int> integerList;
// 添加元素
integerList << 1 << 2;
integerList.append(3);
integerList.insert(0,0);
integerList.prepend(-1);
integerList.push_back(4);
integerList.push_front(5);
//移除
integerList.takeFirst();
integerList.takeLast();
//删除
integerList.removeOne(1);
integerList.removeAll(1);
//查找
bool bOk = integerList.contains(2);
//迭代
QLinkedList<int>::iterator it;
for (it = integerList.begin(); it != integerList.end(); ++it) {
qDebug() << *it;
}
//只读迭代
QLinkedList<int>::const_iterator cit;
for (cit = integerList.constBegin(); cit != integerList.constEnd(); ++cit) {
qDebug() << *cit;
}
QQueue
QQueue 是 QList 的派生类,继承了列表的全部功能,在此基础上新增了dequeue、enqueue、head操作。
QQueue<int> queue;
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3); //入队操作,添加队尾
queue.dequeue(); //出队操作,将队头元素移除
while (!queue.isEmpty())
cout << queue.dequeue() << endl;
//T & head() //获取队头的读写引用
//const T & head() const //获取队头的只读引用
QVector
QVector<T>和其他QT容器、大部分值类型的类(包括 QString)一样,使用隐式共享。但拷贝一个QVector时,内部只是拷贝了一个指针和递增了引用计数,只有修改数据时,才会进行深拷贝,隐式共享也称写时复制。隐式共享是QVector和std::vector<T>的主要区别。QBasicAtomic类用于保存引用计数,支持原子操作(线程安全),确保隐式共享可以跨线程使用。 QT在不同架构下使用汇编语言来实现QBasicAtomic类。为了避免每次容器增长时都分配内存, QVector<T> 会一次分配超过需要的内存。如果参数T是可拷贝类型(可以通过memcpy() or memmove()进行拷贝的对象,例如C++原类型和QT隐式共享类), QVector<T>使用 realloc()一次再分配 4096字节的增量。 这是因为现代操作系统当重新分配一个内存时并不拷贝整块数据,只是物理内存页面简单的重新排序,第一页和最后一页需要进行拷贝。对于不可拷贝数据类型,QVector<T>以每次增长50%的方式,确保在频繁调用append()函数时平均算法复杂度为 O(n)。如果用QVector<T>储存自定义的类型, QT会假定自定义数据类型是不可拷贝类型。对于自定义可拷贝的数据类型,可以使用 Q_DECLARE_TYPEINFO()宏来声明。
//添加
void append(const T & value) //将 value 添加到向量尾部
void push_back(const T & value) //将 value 添加到向量尾部,STL风格
void prepend(const T & value) //将 value 添加到向量头部
void push_front(const T & value) //将 value 添加到向量头部,STL风格
通常情况下,添加到向量尾部的开销比较小,而添加到头部意味着将向量原有的元素都向后平移,开销会很大。
//插入元素
void insert(int i, const T & value)
void insert(int i, int count, const T & value)
第一个 insert() 是将一个 value 插入到序号 i 的位置,原本序号 i 以及后面的元素都平移,然后把 value 复制到序号 i 的位置。
第二个 insert() 是将 count 个 value 值插入到序号 i 的位置,插入后从序号 i 到 i+count-1 序号都是等于 value 值的元素。insert() 函数支持的最大序号是 size() ,即元素总数,如果 i 等于 size() ,那么元素添加到向量末尾。如果 i >size() ,程序会因为访问越界而崩溃。其他带序号 i 的函数,序号范围仅支持 0 ~ size()-1 ,只有 insert() 例外多支持一个添加到末尾。
//计算大小
int count() const
int size() const
int length() const
//移除元素
T takeAt(int i) //卸下序号 i 位置元素,并返回该元素
T takeFirst() //卸下向量的头部元素,并返回该元素
T takeLast() //卸下向量的尾部元素,并返回该元素
//直接删除
void remove(int i) //删除序号 i 位置元素
void removeAt(int i) //删除序号 i 位置元素
void remove(int i, int count) //从序号 i 位置开始删除参数里 count 个数的元素
void removeFirst() //删除头部元素
void pop_front() //删除头部元素,STL风格
void removeLast() //删除尾部元素
void pop_back() //删除尾部元素,STL风格
//删除多个类似
bool removeOne(const T & t) //如果向量里存在等于 t 的元素就删除并返回 true,否则找不到返回 false
int removeAll(const T & t) //删除向量中所有等于 t 的元素,并返回删除的数量
//迭代
QVector<int> va = {1, 2, 3};
QVector<int>::iterator it = va.begin();
while( it != va.end() )
{
qDebug()<< (*it);
it++; //下一个
}
// or
for (int i = 0; i < vector.size(); ++i) {
if (vector.at(i) == "Alfonso")
cout << "Found Alfonso at position " << i << endl;
}
QStack
Qstack继承QVector,提供后入先出结构,在此基础上增加压栈、出站、返回栈顶
void push(const T & t) //将 t 添加到栈顶
T pop() //取出栈顶元素并返回
T & top() //获取栈顶元素的读写引用
const T & top() const //获取栈顶元素的只读引用
T QStack::pop() //出栈 取出栈顶元素并返回
关联容器
关联存储容器中存储的一般是二元组,即键值对。QT提供两种关联容器类型:QMap<K, T>和QHash<K, T>。
QMap
QMap 模板类通常将数据按照 key – value(键-值) 配对的形式存储,程序中以 key 作为序号来查询对应的 value,比如 map[“红色”] = 0xFF0000 。QMap 通常将一个 key 映射为一个 value,而 QMultiMap 通常将 一个 key 映射为多个 value,这就是单映射和多映射(QMultiMap )的区别。使用红黑树的好处:
- 在插入、删除和查找操作上,红黑树可以保持对数时间复杂度(O(log n)),这使得
std::map
具有较高的性能。- 二叉搜索树保证了元素的有序性,这意味着我们可以很容易地对
std::map
进行顺序访问。- 自平衡特性保证了即使在最坏情况下,树的高度也保持在log(n),这避免了性能下降。
QMap<QString, int>NameAge = {{"andle",5},{"mell",10},{"ancoll", 8} };
QMap<QString, int>TempNameAge = std::move(NameAge);
qDebug()<< NameAge;
qDebug()<< TempNameAge;
//添加
NameAge.insert("mrain",9);
NameAge["andle"] = 9;
qDebug()<< NameAge;
qDebug()<< TempNameAge;
移除和删除函数
从映射对象卸下一个元素,但不释放空间,使用下面函数:T take(const Key & key)
返回值 T 是 value 类型的数值。如果映射对象里根本没有指定 key,那么返回值是 value 类型默认构造函数生成的对象。
如果不需要返回值,直接从映射对象删除指定 key 及其 value,使用下面函数:int remove(const Key & key)
返回值是删除元素的个数,如果返回值为 0,说明映射里没有该 value;如果为 1 ,说明正好删除了一对 key – value ;如果返回值大于1,说明程序之前使用 insertMulti() 函数为一个 key 添加了多个 value 值(QMap 允许一对多映射,多个 key-value 元素 的 key 值相同,但一般不建议这样做)。
如果希望清空所有元素,那么使用如下函数:void clear()
访问和查询函数
查询映射对象内是否包含 key 键:bool contains(const Key & key) const
查询映射对象内所有元素数目:
int count() const int size() const
统计 key 对应的 value 值数量,使用下面函数:
int count(const Key & key) const
如果映射对象不存在 key 键,那么返回值为 0,如果存在一对 key-value ,那么返回值为 1;如果程序之前使用 insertMulti() 函数为一个 key 添加了多个 value,那么返回值是多个 value 值的数量。
判断映射对象是否全空,没有元素,使用下面两个函数都可以:bool empty() const //STL风格 bool isEmpty() const //Qt风格
获取映射中第一个 value 值,使用下面函数:T & first() const T & first() const
获取映射中第一个 key 键,使用下面函数:
const Key & firstKey() const
获取映射中最后一个 value 值,使用下面函数:
T& last() const T& last() const
获取映射中最后一个 key 键,使用下面函数:
const Key & lastKey() const
根据已知 value 值反查归属的 key 键:const Key key(const T & value, const Key & defaultKey = Key()) const
反查耗时比较长,需要逐个遍历元素,注意多个 key 对应的 value 可能一样,所以上面函数只返回第一个匹配的 key。如果找不到就返回默认构造的 Key() 。
如果要根据 value 反查所有匹配的 key 键列表,使用下面函数:QList<Key> keys(const T & value) const
如果需要获取映射所有元素的 key 值列表,使用下面函数:
QList<Key> keys() const
注意 insertMulti() 函数可能导致多个 key-value 元素的 key 值一样,keys() 获取的键值是可能重复的。如果希望获取不重复出现的 key 列表,使用下面函数:
QList<Key> uniqueKeys() const
根据 key 查询对应 value ,使用下面函数:
const T value(const Key & key, const T & defaultValue = T()) const
如果没有找到 key-value 元素,那么返回 T() 值,就是 value 类型默认构造值。
存在一对多映射的情况下,可以用下面函数获取 key 对应的多个 value 值列表:QList<T> values(const Key & key) const
如果要获取映射中所有元素的 value 值列表,使用下面函数:
QList<T> values() const
QMultiMap
QMultiMap 是 QMap 的派生类,继承了 QMap 绝大多数的功能函数,同时也根据一对多映射(一个key对应多个val)的特性做了改进,将基类的部分函数功能进行了重载
QMultiMap::QMultiMap () //默认构造函数
QMultiMap::QMultiMap ( const QMap<Key, T> & other ) //复制构造函数从QMap到QMultiMap
//也支持移动构造
QMultiMap<QString, QString> namePhone{
{"Alice", "10086"},
{"Alice", "10087"},
{"Bob", "10010"},
{"Bob", "10011"}
};
qDebug()<<namePhone;
QMultiMap<QString, QString> namePhone2( namePhone );
qDebug()<<namePhone2;
QMultiMap<QString, QString> namePhone3 = std::move(namePhone);
qDebug()<<namePhone<<endl<<namePhone3;
/*输出
QMap(("Alice", "10087")("Alice", "10086")("Bob", "10011")("Bob", "10010"))
QMap(("Alice", "10087")("Alice", "10086")("Bob", "10011")("Bob", "10010"))
QMap()
QMap(("Alice", "10087")("Alice", "10086")("Bob", "10011")("Bob", "10010"))
*/
因为QMultiMap是从QMap继承过来的主要说说不同点
添加函数
QMap<Key, T>::iterator QMultiMap::insert(const Key & key, const T & value)
QMap<Key, T>::iterator QMultiMap::insert(QMap<Key, T>::const_iterator pos, const Key & key, const T & value)QMultiMap 的迭代器完全从基类 QMap 继承,因此可以看到参数和返回值的迭代器都是 QMap 的迭代器。但要注意 QMultiMap::insert() 总是插入新的 key-value 节点,不会对旧节点进行替换,即使新旧节点键值一模一样,也会增加新的节点。
第一个 insert() 自动添加新节点到红黑树的排序位置,红黑树只按照 key 排序,同样 key 的多个 value 值不会排序,同样 key 的新节点总是插入到同样 key 旧节点的最前面。
第二个 insert() 会在建议的迭代器位置 pos 附近插入新节点,但不一定是指定位置,最终还是要按红黑树的 key 进行排序确定位置。
删除函数
需要注意的是remove,是删除所有键为key的value
[]操作
QMap是没有值就添加,有值就覆盖,QmultiMap没有[]操作,添加typename QMap<Key, T>::iterator replace(const Key &key, const T &value)
迭代器
容器类提供了两种风格的迭代器:Java风格和STL风格。Java风格迭代器比较容易使用,STL风格迭代器则可以用在一些通用算法中,功能比较强大
// Java风格
QList<double> list;
// …
QListIterator<double> i(list);
while (i.hasNext()) {
doSomethingWith(i.next());
}
// STL风格
QList<QString> list;
list << “A” << “B” << “C” << “D”;QList<QString>::iterator i;
for (i = list.begin(); i != list.end(); ++i)
*i = (*i).toLower();
需要注意迭代器的隐式共享和删除失效
QVector<int> a, b;
a.resize(100); //向量初始化为100个0
// i 指向向量第一个元素
QVector<int>::iterator i = a.begin();
//隐式共享,b 和 a 指向同一块存储空间
b = a;
//隐式共享在一个对象发生变化后,为变化的对象分配新空间,并赋值
// a 元素修改后,i 迭代器与 a 无关了!!!
// i 其实指向 b 首元素,因为 b 没有修改,使用旧的内存空间
a[0] = 5;
//这时候 *i 是 b 开头的数值 0
b.clear(); //清空 b,那么迭代器 i 就属于野指针!!!
// 迭代器的错误示范
int j = *i; //野指针使用,未知结果
迭代器 i 原本指向 a 的空间,但是隐式共享特性是谁改变数值,就给谁分配新空间,修改 a[0] 之后,迭代器 i 其实已经处于异常状态,已经与 a 无关了。
这时候 i 仍然指向 b,那么一旦 b 清除空间,i 就成了野指针,这是非常危险的,可能导致内存错误,程序异常结束。
因此,使用迭代器时,一定要注意使用最新的迭代器赋值,不要用旧的过期的迭代器。
隐式共享对象元素的增删改都可能导致迭代器失效
,如果不清楚状况,那最好的做法是复制一个常量对象,对常量对象使用只读迭代器:
// OK
const QList<int> sizes = splitter->sizes();
QList<int>::const_iterator i;
for (i = sizes.begin(); i != sizes.end(); ++i)
...
如果没有使用隐式共享,只是一个对象一个存储空间,那么可以放心使用迭代器,迭代过程中删除元素应该使用专门的迭代器函数 erase(), erase() 会返回下一个元素迭代器位置,
迭代循环过程中一般不要使用 remove(),remove() 可能导致之前的迭代器失效
。
在迭代过程正确删除元素的示范代码如下:QHash<QString, int>::iterator i = hash.begin();
while (i != hash.end())
{
if (i.key().startsWith(“_”))
i = hash.erase(i);
else
++i;
}或者保存旧元素的迭代器,提前移动到下一个元素位置,然后删除旧元素迭代器位置:
QHash<QString, int>::iterator i = hash.begin();
while (i != hash.end())
{
QHash<QString, int>::iterator prev = i;
++i;
if (prev.key().startsWith(“_”))
hash.erase(prev);
}
错误示范
上面代码一般情况下不会出错,但是不建议这么写,这段代码的问题在于,当删除list1中的元素时,会导致后面的元素索引发生变化(其实就是size变化了),导致循环遍历不完整或者出现越界访问等问题。
也可以这样写:从后往前遍历list1,这样删除元素时不会对后面的元素造成影响。修改后的代码如下
QList<int> list1;
list1 << 1 << 2 << 3 << 4;
for(int i = list1.size() - 1; i >= 0; i--)
{
if(list1[i] == 2)
{
list1.removeAt(i);
}
qDebug() << list1[i] << list1.size();
}