您现在的位置是:首页 >技术交流 >容器中的operator[]注意事项网站首页技术交流

容器中的operator[]注意事项

-西门吹雪 2024-06-17 11:26:41
简介容器中的operator[]注意事项

首先看一张表格,支持operator[]的容器包括stringarrayvectordequemapunordered_map,顺序容器和关联容器的operator[]不太一致。
在这里插入图片描述

string中的operator[]

pos < size()时返回到位于指定位置pos的字符的引用,或在pos == size()时返回到拥有值CharT()的字符(空字符)的引用。不进行边界检查。
如果 pos > size(),那么行为未定义。

int main() {
    std::string const e("Exemplar");
    for (unsigned i = e.length() - 1; i != 0; i /= 2)
        std::cout << e[i];
    std::cout << '
';
 
    const char* c = &e[0];
    std::cout << c << '
'; // 作为 C 字符串打印
    // 将 s 的最后一个字符改成 'y'
    std::string s("Exemplar ");
    s[s.size() - 1] = 'y';
    std::cout << s << '
';
    return 0;
}

运行结果

rmx
Exemplar
Exemplary

Array中的operator[]

返回位于指定位置 pos 的元素的引用。不进行边界检查。
不同于std::map::operator[]此运算符决不插入新元素到容器。通过此运算符访问不存在的元素是未定义行为。

#include <iostream>
#include <map>
#include <string>
#include <string_view>
#include <vector>
#include <array>

using namespace std;
int main() {
    std::array<int,4> numbers {2, 4, 6, 8};

    std::cout << "Second element: " << numbers[1] << '
';
 
    numbers[0] = 5;
 
    std::cout << "All numbers:";
    for (auto i : numbers) {
        std::cout << ' ' << i;
    }
    std::cout << '
';
    return 0;
}

运行结果

Second element: 4
All numbers: 5 4 6 8

vector中的operator[]

返回位于指定位置 pos 的元素的引用。不进行边界检查。

#include <vector>
#include <iostream>
 
int main()
{
    std::vector<int> numbers {2, 4, 6, 8};
 
    std::cout << "Second element: " << numbers[1] << '
';
 
    numbers[0] = 5;
 
    std::cout << "All numbers:";
    for (auto i : numbers) {
        std::cout << ' ' << i;
    }
    std::cout << '
';
}

运行结果

Second element: 4
All numbers: 5 4 6 8

deque中的operator[]

reference       operator[]( size_type pos );	
const_reference operator[]( size_type pos ) const;

返回位于指定位置 pos 的元素的引用。不进行边界检查。

#include <deque>
#include <iostream>
 
int main()
{
    std::deque<int> numbers {2, 4, 6, 8};
 
    std::cout << "Second element: " << numbers[1] << '
';
 
    numbers[0] = 5;
 
    std::cout << "All numbers:";
    for (auto i : numbers) {
        std::cout << ' ' << i;
    }
    std::cout << '
';
}

运行结果

Second element: 4
All numbers: 5 4 6 8

map中的operator[]

T& operator[]( const Key& key );(1) 	
T& operator[]( Key&& key );(2) 	(C++11)

返回到映射到等于key的键的值的引用,这种键不存在的情况下就会进行插入。

  1.  (`C++11 `前) 在键不存在的情况下插入` value_type(key, T())`
    
  • key_type 必须符合可复制构造 (CopyConstructible) 的要求。
  • mapped_type 必须符合可复制构造 (CopyConstructible) 和 可默认构造 (DefaultConstructible) 的要求。
    如果进行插入,那么值初始化被映射值(对类类型为默认构造,否则为零初始化)并返回到它的引用
  1. c++11
  • 在键不存在的情况下插入从std::piecewise_construct, std::forward_as_tuple(key), std::tuple<>()原位构造的 value_type 对象。此函数等价于 return this->try_emplace(key).first->second;。 (C++17 起)
    使用默认分配器时,这导致从 key 复制构造键,并值初始化被映射值。
  • value_type 必须从std::piecewise_construct, std::forward_as_tuple(key), std::tuple<>()可就位构造(EmplaceConstructible)。使用默认分配器时,这表明key_type必须可复制构造 (CopyConstructible) 而 mapped_type 必须可默认构造 (DefaultConstructible) 。
  1. 在键不存在的情况下插入从std::piecewise_construct, std::forward_as_tuple(std::move(key)), std::tuple<>()原位构造的value_type对象。此函数等价于 return this->try_emplace(std::move(key)).first->second; 。 (C++17 起)
    使用默认分配器时,这导致从key移动构造键,并值初始化被映射值。
  • value_type 必须从std::piecewise_construct, std::forward_as_tuple(std::move(key)), std::tuple<>()可就位构造 (EmplaceConstructible) 。使用默认分配器时,这表明 key_type 必须为可移动构造 (MoveConstructible) 而 mapped_type 必须为可默认构造 (DefaultConstructible) 。

参数

key - 要寻找的元素键

返回值

不存在拥有键key的元素时返回到新元素被映射值的引用。否则返回到既存的关键等价于 key 的元素的被映射值的引用。

异常

如果任何操作抛出异常,那么插入无效果。

注解

出版的 C++11 C++14标准中,指定此函数要求mapped_type为可默认插入 (DefaultInsertable) 且 key_type 为可复制插入 (CopyInsertable) 或可移动插入 (MoveInsertable) 到 *this。此规定有缺陷并为LWG问题2469 所修复,而上面的描述合并了该问题的解决方案。

然而,已知一个实现(libc++)通过两个分离的分配器construct()调用构造key_type mapped_type 对象,可认为如发布时的标准所要求,而非原位构造 value_type 对象。
operator[] const,因为它会在键不存在时插入键。如果此行为非所欲或容器为 const,那么可以使用 at()
insert_or_assign() 返回的信息多于 operator[],而且不要求mapped_type可默认构造。(C++17 起)

#include <iostream>
#include <map>
#include <string>

auto print = [](auto const comment, auto const& map) {
    std::cout << comment << "{";
    for (const auto& pair : map)
        std::cout << "{" << pair.first << ": " << pair.second << "}";
    std::cout << "}
";
};

int main() {
    std::map<char, int> letter_counts{{'a', 27}, {'b', 3}, {'c', 1}};

    print("letter_counts 初始状态下包含:", letter_counts);

    letter_counts['b'] = 42;  // 更新既存值
    letter_counts['x'] = 9;   // 插入新值

    print("修改后它包含:", letter_counts);

    // 统计每个单词的出现次数
    // (首次调用 operator[] 会初始化计数为零)
    std::map<std::string, int> word_map;
    for (const auto& w : {"this", "sentence", "is", "not", "a", "sentence",
                          "this", "sentence", "is", "a", "hoax"})
        ++word_map[w];
    word_map["that"];  // 插入对 {"that", 0}

    for (const auto& [word, count] : word_map)
        std::cout << "单词 '" << word << "' 出现 " << count << "次
";
}

运行结果,注意这个 word_map["that"]; // 插入对 {"that", 0} 是插入了一个map值

letter_counts 初始状态下包含:{{a: 27}{b: 3}{c: 1}}
修改后它包含:{{a: 27}{b: 42}{c: 1}{x: 9}}
单词 'a' 出现 2次
单词 'hoax' 出现 1次
单词 'is' 出现 2次
单词 'not' 出现 1次
单词 'sentence' 出现 3次
单词 'that' 出现 0次
单词 'this' 出现 2

unordered_map中的operator[]

T& operator[]( const Key& key );(1) 	(C++11)
T& operator[]( Key&& key );(2) 	(C++11)

返回到映射到等于 key 的键的值的引用,这种键不存在的情况下就会进行插入。

#include <iostream>
#include <string>
#include <unordered_map>
 
auto print = [](auto const comment, auto const& map)
{
    std::cout << comment << "{";
    for (const auto &pair : map)
        std::cout << "{" << pair.first << ": " << pair.second << "}";
    std::cout << "}
";
};
 
int main()
{
    std::unordered_map<char, int> letter_counts{{'a', 27}, {'b', 3}, {'c', 1}};
 
    print("letter_counts 初始状态下包含:", letter_counts);
 
    letter_counts['b'] = 42; // 更新既存值
    letter_counts['x'] = 9;  // 插入新值
 
    print("修改后它包含:", letter_counts);
 
    // 统计每个单词的出现次数
    // (首次调用 operator[] 会初始化计数为零)
    std::unordered_map<std::string, int>  word_map;
    for (const auto& w : {"this", "sentence", "is", "not", "a", "sentence",
                          "this", "sentence", "is", "a", "hoax"})
        ++word_map[w];
    word_map["that"]; // 插入对 {"that", 0}
 
    for (const auto& [word, count] : word_map)
        std::cout << "单词 '" << word << "' 出现 " << count << "次
";
}

运行结果

letter_counts 初始状态下包含:{{c: 1}{b: 3}{a: 27}}
修改后它包含:{{x: 9}{c: 1}{b: 42}{a: 27}}
单词 'a' 出现 2次
单词 'not' 出现 1次
单词 'is' 出现 2次
单词 'that' 出现 0次
单词 'hoax' 出现 1次
单词 'sentence' 出现 3次
单词 'this' 出现 2

参考

官网容器

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。