C++常见避坑指南( 四 )


在实际编程中 , 还是不太建议使用全局静态对象,建议的写法:
要声明全局的常量字符串,可以使用 const 关键字和 extern 关键字的组合:
// constants.hextern const char* GLOBAL_STRING;// constants.cpp#include "constants.h"const char* GLOBAL_STRING = "Hello, world!";constexpr char* kVal="hahhahah";使用 constexpr 关键字来声明全局的常量字符串:// constants.hconstexpr const char* GLOBAL_STRING = "Hello, world!";迭代器删除在处理缓存时 , 容器元素的增删查改是很常见的 , 通过迭代器去删除容器(vector/map/set/unordered_map/list)元素也是常有的,但这其中使用不当也会存在很多坑 。
std::vector<int> numbers = { 88, 101, 56, 203, 72, 135 };auto it = std::find_if(numbers.begin(), numbers.end(), [](int num) {    return num > 100 && num % 2 != 0;});vec.erase(it);上面代码,查找std::vector中大于 100 并且为奇数的整数并将其删除 。std::find_if 将从容器的开头开始查找,直到找到满足条件的元素或者遍历完整个容器,并返回迭代器it , 然后去删除该元素 。但是这里没有判断it为空的情况,直接就erase了,如果erase一个空的迭代器会引发crash 。很多新手程序员会犯这样的错误,随时判空是个不错的习惯 。
删除元素不得不讲下std::remove 和 std::remove_if,用于从容器中移除指定的元素,函数会将符合条件的元素移动到容器的末尾,并返回指向新的末尾位置之后的迭代器,最后使用容器的erase来擦除从新的末尾位置开始的元素 。
std::vector<std::string> vecs = { "A", "", "B", "", "C", "hhhhh", "D" };vecs.erase(std::remove(vecs.begin(), vecs.end(), ""), vecs.end());// 移除所有偶数元素vec.erase(std::remove_if(vec.begin(), vec.end(), [](int x) { return x % 2 == 0; }), vec.end());这里的erase不用判空,其内部实现已经有判空处理 。
_CONSTEXPR20 iterator erase(const_iterator _First, const_iterator _Last) noexcept(        is_nothrow_move_assignable_v<value_type>) /* strengthened */ {    const pointer _Firstptr = _First._Ptr;    const pointer _Lastptr  = _Last._Ptr;    auto& _My_data          = _Mypair._Myval2;    pointer& _Mylast        = _My_data._Mylast;    // ....    if (_Firstptr != _Lastptr) { // something to do, invalidate iterators        _Orphan_range(_Firstptr, _Mylast);        const pointer _Newlast = _Move_unchecked(_Lastptr, _Mylast, _Firstptr);        _Destroy_range(_Newlast, _Mylast, _Getal());        _Mylast = _Newlast;    }    return iterator(_Firstptr, _STD addressof(_My_data));}此外,STL容器的删除也要小心迭代器失效,先来看个vector、list、map删除的例子:
// vector、list、map遍历并删除偶数元素std::vector<int> elements = { 1, 2, 3, 4, 5 };for (auto it = elements.begin(); it != elements.end();) { if (*it % 2 == 0) {        elements.erase(it++);    } else {        it++;    }}// Errorstd::list<int> cont{ 88, 101, 56, 203, 72, 135 };for (auto it = cont.begin(); it != cont.end(); ) {    if (*it % 2 == 0) {        cont.erase(it++);    } else {        it++;    }}// Ok std::map<int, std::string> myMap = { {1, "one"}, {2, "two"}, {3, "three"}, {4, "four"}, {5, "five"} };// 遍历并删除键值对 , 删除键为偶数的元素for (auto it = myMap.begin(); it != myMap.end(); ) {    if (it->first % 2 == 0) {        myMap.erase(it++);    } else {        it++;    }}// Ok


推荐阅读