我有以下代码,它使用map根据键将节点插入 mp 。该类有两个函数 set 和 get 分别插入和访问映射。
struct Node {
int value;
int key;
Node(int k, int val):key(k),value(val) {};
};
class Cache {
private:
map<int, Node*> mp;
Node* tail;
Node* head;
public:
void set(int, int);
void get(int);
};
void Cache::set(int key, int value) {
Node newN = Node(key, value);
mp.insert(std::pair<int, Node*>(key, &newN));
}
void Cache::get(int key) {
auto s = this->mp.find(key);
if (s != this->mp.end()) {
Node *nHit = s->second;
std::cout << "Map key = " << s->first;
std::cout << " : Node Key = " << nHit->key;
std::cout << ", value = " << nHit->value << "\n";
}
}
下面是驱动程序主要功能实现,它接受2行输入并输出键和值。
int main() {
int i;
Cache l;
for(i = 0; i < 2; i++) {
string command;
cin >> command;
if(command == "get") {
int key;
cin >> key;
l.get(key);
}
else if(command == "set") {
int key, value;
cin >> key >> value;
l.set(key, value);
}
}
return 0;
}
输入 -
设置2 3
得到2
输出 -
Map key = 2:Node Key = 32764,value = -491659096
注意 - 输出键和值会不断变化,并且不会在每次运行时修复。
为什么以及如何更改地图的键和值?
答案 0 :(得分:1)
您正在插入指向函数范围值的指针。当函数set()退出时,newN被销毁,并且地图中保存的指针无效。
要么你真的想要一个带有Node实例的地图作为价值;或者你需要在set()中使用new来分配你的对象,但是你还需要记住删除它。您可以使用“智能”指针(例如shared_ptr或unique_ptr)来帮助管理此生命周期 - 尽管unique_ptr不会比使用实例更有优势。
答案 1 :(得分:0)
在C ++中,一段数据通常绑定到一个位置。如果该位置是某个{ block scope; }
中的变量,则在结束}
处删除该变量。例如,Cache::set
的右括号会删除newN
,对它的任何引用(包括mp
中的指针)都不再指向任何位置。
C ++有第二种选择:某些数据的生命周期可以由一个类控制。例如,您放入int
的{{1}}和Node*
值与mp
一起被删除。因此,不是将mp
存储在mp中,而是直接存储Node*
,而不是其地址!
Node
的声明应为
mp
您可以使用
进行插入map<int, Node*> mp;
然后在void Cache::set(int key, int value) {
mp.emplace(key, Node(key, value));
}
中你可以拥有
main
然后,您可以Node &nHit = s->second;
成员nHit
而不是.
。
另一种选择是使用智能指针,正如Jesper Juhl所说。将->
存储在std::unique_ptr<Node>
中,如果您只使用指针进行虚拟方法的多态操作,mp
如果您想要使用某些std::shared_ptr<Node>
个对象则非常有用在几个地方和 Node
。
如果您想要引用已知生命周期的对象,并且想要将该引用存储在某些内容中,则使用mp
(例如创建&
)对象的地址非常有用生命周期较短的其他对象。
请勿在智能指针构造函数中使用Node*
,除非您已准备好自己单独new Node(key, value)
每个 delete
,并且永远不要错误。
答案 2 :(得分:-1)
您必须使用new
分配节点。如,
Node *newN = new Node(key, value);
mp.insert(std::pair<int, Node*>(key, newN));
因为它是你的节点在堆栈上并且在函数返回时超出范围。