如何解决C ++映射,使用const引用作为值类型,这是什么问题? 代码示例1 代码示例2 代码示例3
今天,我看到了老板的代码,该代码使用const引用作为map
的值类型。
这是代码:
class ConfigManager{
public:
map<PB::Point,const PB::WorldPoint&,compare_point> world_point;
//the rest are omitted
};
({PB
是Google Protobuf,我们使用的是Protobuf库。我对此了解不多,或者与问题是否相关。)
该类的作用是读取一些配置文件,并将其放入map
个文件中进行搜索。
起初我很惊讶,因为我还没有看到map
的引用作为其值,例如map<int,classA&> aMap
。
然后我搜索了SO,这两个问题告诉我我不能这样做。
C++: Is it possible to use a reference as the value in a map?
STL map containing references does not compile
然后我尝试了这段代码,确实无法编译:
代码示例1
struct A {
int x = 3;
int y = 4;
};
map<int,A&> myMap;
int main() {
A a;
myMap.insert(make_pair(1,a));
}
但是如果我将map<int,A&> myMap;
更改为map<int,const A&> myMap;
,它将编译。
但是发生了另一个问题。使用map<int,const A&> myMap;
,我无法使用[]
来获得货币对,但是我可以使用map.find()
。
(老板告诉我使用map.find()
后不能使用[]
。
代码示例2
struct A {
int x = 3;
int y = 4;
};
map<int,const A&> myMap;
int main() {
A a;
myMap.insert(make_pair(1,a));
//can't compile
cout << myMap[1].x << " " << myMap[1].y << endl;
//can work
//auto it = myMap.find(1);
//cout << it->second.x << " " << it->second.y << endl;
}
所以直到现在,我一直认为我的老板是正确的。他的代码是正确的。
最后一个故事是我向一些在线朋友展示了该代码。他们注意到了一个问题。
代码示例3
#include <map>
#include <iostream>
#include <string>
using namespace std;
struct A {
int x = 3;
int y = 4;
~A(){
cout << "~A():" << x << endl;
x = 0;
y = 0;
}
};
map<string,const A&> myMap;
int main() {
A a;
cout << a.x << " " << a.y << endl;
myMap.insert(make_pair("love",a));
a.x = 999;
cout << "hello" << endl;
auto s = myMap.find("love");
cout << s->second.x << " " << s->second.y << endl;
}
输出为:
3 4
~A():3
hello
0 0
~A():999
如果我正确理解了输出(如果我弄错了请纠正我),则表明:
-
make_pair("love",a)
创建一个对象pair<"love",temproray copy of a>
。一对将inserted
放入myMap
。 - 以某种方式,我不知道它是如何发生的,
temporary copy of a
立即被破坏。对我来说,这意味着temporary copy of a
的内存现在不归任何人所有,如果我理解正确的话,它现在是可以用任何值填充的内存的可用空间。
所以现在我又变得困惑了。
我的问题是:
-
代码示例3 会怎样?我的理解正确吗?为什么在声明后
temporary copy of a
被破坏?不使用const引用可以延长临时对象的寿命吗?我的意思是,我认为在main
完成之前不应该破坏它。 -
我老板的代码不正确并且非常危险吗?
解决方法
为什么在语句后立即破坏了临时副本?
因为(在大多数情况下)临时人员是这样工作的。有效期至创建它们的语句的末尾。在这种情况下,暂时寿命的扩展名不适用,请参见here。 TLDR版本是
通常,不能通过以下方式进一步延长临时期限 “传递”:第二个引用,从引用初始化为 绑定的临时对象,不会影响其寿命。
我可以使用const引用作为地图的值类型吗?
是的,只要您意识到向映射添加const引用对所引用对象的生存期没有影响。您的老板代码也不正确,因为make_pair
返回的临时文件在语句末尾被销毁了。
您可以改用std:: unique_ptr<A>
。然后用emplace
代替insert
:
using value_t=std:: unique_ptr<A>;
std::map<int,value_t> myMap;
myMap.emplace(1,new A);
myMap[1]=new A{5,6};
myMap[1]->x=7;
有关std:: unique_ptr<A>
的更多信息:
https://en.cppreference.com/w/cpp/memory/unique_ptr
代码示例3会怎样?我的理解正确吗?
您的解释已经结束。 std::pair
返回的std::make_pair
是临时对象。临时std::pair
包含a
的副本。在表达式的末尾,该对被破坏,这也破坏了其元素,包括a
的副本。
为什么在语句后立即破坏了临时副本?不使用const引用可以延长临时对象的寿命吗?我的意思是,我认为在主体完成之前不应破坏它。
这里的临时变量是std::make_pair
的结果,该结果被用作成员函数insert
的参数。这里适用的相关规则是:
无论何时将引用绑定到临时对象或其子对象,临时对象的生存期都会延长以匹配引用的生存期,但以下情况除外:
- [...]
- 在函数调用中存在与参考参数的临时绑定,直到包含该函数调用的完整表达式的结尾[...]
- [...]
包含函数调用的完整表达式为表达式myMap.insert(make_pair(1,a));
,这意味着std::make_pair
的结果的生存期在函数返回后(包括其中包含的A
)结束。新的std::map
元素将引用临时A
中的std::pair
,一旦insert
返回,该元素就会悬空。
我老板的代码不正确并且非常危险吗?
是的,myMap
包含悬空的引用。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。