从C map返回值返回相同的对象
我创建了一个类型为map< T,const T&>的地图.对于当前的示例目的,假设T是:
class Bar { public: Bar(int x) {this->x = x;} int x; }; 接下来,我创建一个地图并插入以某些整数键入的条形图. Bar bs[] = {Bar(1),Bar(2),Bar(3)}; map<int,const Bar&> my_map; for (int i = 0; i < 3; i++) { const Bar &b = bs[i]; cout << "Setting map." << i << " with x = " << b.x << endl ; my_map.insert(std::make_pair(i,b)); } 到目前为止,一切看起来都很好,而b.x打印的值为1; 2; 3如预期.接下来,我们将检索这些值. for (int i = 0; i < 3; i++) { auto iter = my_map.find(i); if (iter == my_map.end()) { cout << "Not found!" << endl; continue; } cout << "map." << i << " = " << iter->second.x << endl; } 输出每次打印最后一个值,如下所示. // map.0 = 3 // map.1 = 3 // map.2 = 3 这就是让我困惑的事情,正如我所期待的那样; 2; 3.如果我用const Bar替换地图的值类型,它给出1; 2;我一直试图理解它,但到目前为止它看起来像是未定义的行为.我能想象的最疯狂的解释是& b就像一个存储指向对象的指针的盒子,并且盒子最终在循环中共享,而make_pair使用& b作为盒子值而不是指针/参考(因此解释了最后打印的值). 编辑:我理解使用这样的地图可能不是一个好主意,但我很好奇为什么会发生这种情况而不是我应该使用的.从语义上讲,当我写这篇文章时,我错过了什么以及为什么它通过编译器,或者为什么编译器做出了任何假设. 编辑:运行代码的repl.it上的示例:https://repl.it/repls/IgnorantExhaustedBluejay 解决方法
基本上与此处相同的问题:
How can I have a pair with reference inside vector?
您对std :: make_pair的调用会创建一个临时的std :: pair对象,该对象没有引用作为其第二个成员.该对的第二个成员是Bar类型的常规值.同时,您的地图存储引用.引用绑定到std :: make_pair创建的临时的第二个成员.后来临时被摧毁了.引用变得晃来晃去. 循环的每次迭代中的每个临时值显然都是在内存中的相同位置创建的.因此,地图中的所有这些悬空引用都指向内存中的相同位置.这恰好恰好在打印时保持3的残值.这解释了输出. 带有原始引用的地图不是一个好主意.但是如果你想以某种方式强制它使用原始引用,请停止使用std :: make_pair.相反,手动构造一个正确的std :: pair,确保明确指定正确的类型 my_map.insert(std::pair<const int,const Bar &b>(i,b)); 或者您可以按如下方式继续使用std :: make_pair my_map.insert(std::make_pair(i,std::cref(b))); 但完全切换到std :: reference_wrapper和std :: cref是个更好的主意. 附:顺便说一下,在C17模式下,GCC拒绝使用原始引用编译代码. C 14模式确实编译它. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |