【问题标题】:return value of map operator[] (and "at" method)map operator[](和“at”方法)的返回值
【发布时间】:2013-10-24 05:43:26
【问题描述】:

我有以下示例代码来解释我的问题。根据 STD 映射容器文档 (http://www.cplusplus.com/reference/map/map/operator%5B%5D/),operator[](或“at”方法)返回对映射值的引用。我明白为什么第 13 行编译并正常工作(当我将元素插入 vec1 时,map 中的映射值得到更新)。我不明白为什么第 13 行不会导致编译错误,因为 vec1 不是引用并且 operator[] 返回引用。

  1 #include <map>
  2 #include <vector>
  3
  4 using namespace std;
  5
  6 int main()
  7 {
  8     map<int, vector<int> > port;
  9
 10     port[1] = vector<int>(1, 10);
 11
 12     vector<int> &vec1 = port[1];    // <===
 13     vector<int> vec2 = port[1];   // <===
 14
 15     return 0;
 16 }

我想也许 operator[] 的实际实现被重载以返回两种类型(值和引用)。但是,当我查看“map”头文件时,它似乎没有(除非我遗漏了什么):

文件:/usr/include/c++/4.7/profile/map.h

      // 23.3.1.2 element access:
      mapped_type&
      operator[](const key_type& __k)
      {
        __profcxx_map_to_unordered_map_find(this, size());
        return _Base::operator[](__k);
      }

#ifdef __GXX_EXPERIMENTAL_CXX0X__
      mapped_type&
      operator[](key_type&& __k)
      {
        __profcxx_map_to_unordered_map_find(this, size());
        return _Base::operator[](std::move(__k));
      }
#endif   

有人可以帮我理解一下吗?

【问题讨论】:

  • 但是vec1 一个参考。
  • 对不起,我的意思是第 13 行,其中 vec2 不是参考。 (我更正了我原来的问题)。

标签: c++ c++11 map stl


【解决方案1】:

类型通常可以从引用中复制构造。所以vec2 只是port[1] 返回的引用所引用的值的副本。这是一个涉及ints的更简单的例子:

int i = 42;
int j& = i; // j is a reference to i
int k = j;  // k is a copy of the int that j refers to, i.e. i.

关于您对两种返回类型的假设,您不能通过返回值重载函数。

【讨论】:

  • 谢谢。您对“c++ copy-constructible”的解释和进一步阅读澄清了正在发生的事情和原因。 (cplusplus.com/reference/type_traits/is_copy_constructible)
  • 我不小心遇到了这个问题,因为我在声明 vec 类型时忘记放 & (如第 13 行),我花了一段时间才弄清楚这个问题。这似乎是一个容易犯的错误,后果很严重。有没有办法可以打开一些编译器选项来对这种情况发出警告。
  • @AhmedA 我怀疑任何编译器都会发出警告,因为它是完全合法的。将引用绑定到返回值是不常见的。典型的用例是做类似post[1].push_back(42) 等的事情。
【解决方案2】:

第 12 行将 vec1 初始化为对 port[1] 的引用(或者更准确地说,port[1] 引用的 vector&lt;int&gt; 对象)。所以对vec1 的任何更改也会更改port[1]

第 13 行将vec2 初始化为port[1]副本。所以对vec2 的任何更改都不会影响port[1]

【讨论】:

    【解决方案3】:

    不确定我是否正确理解了您的问题,因此,我将尝试在第 12 行和第 13 行中向您解释发生了什么。

    vector<int> &vec1 = port[1];
    

    在这里,您正在创建一个向量的引用,并使用port[1] 对其进行初始化。所以,事实上,它们现在指向同一个内存位置。

    vector<int> vec2 = port[1];
    

    在这里,您正在创建一个新向量并将所有数据从port[1] 复制到它。它们包含相同的数据,但它们没有指向相同的内存位置。

    所以,如果你这样做:

    vec1.push_back(1);
    vec2.push_back(2);
    

    您会看到,port[1] 现在包含一个新的附加元素 - 1

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-25
      • 1970-01-01
      • 2023-03-09
      相关资源
      最近更新 更多