从std::map获取值,这是一个用户定义的类对象,导致读取无效



为了简单起见,我正在创建一个模拟问题的演示程序。

在下面的程序中,当我尝试使用worksFineWithPointer函数访问映射时,一切都很好,即存储从映射中提取的值的地址,结果也是预期的,当我试图使用问题功能访问映射时(即将值存储在对象中(,它不会显示预期的结果。

我试着用Valgrind运行我的错误函数,它显示了很多无效的读取请求。但理解valgrind对我来说相当困难,所以没有得到太多(如果可以推荐一本简单的书或在线参考,那也很棒(。如果我注释掉问题函数,则没有valgrind错误。

然后我用电栅栏编译了这个程序,它立即卸芯,我知道哪条线路有问题,如下所示:

#10 0x0000000000401721 in Node::operator= (this=0x7ffccb72e720, obj=...) at test.cc:33
#11 0x0000000000401b83 in A::problem (this=0x7ffccb72e7c8, prefix="test") at test.cc:102
#12 0x0000000000401350 in main () at test.cc:114
(gdb) f 11
#11 0x0000000000401b83 in A::problem (this=0x7ffccb72e7c8, prefix="test") at test.cc:102
102                 crawler = crawler.getMap()[ch];

不确定上面一行的错误,它只会调用operator=,值应该被复制到crawler对象中。可能我在这里遗漏了一些C++的概念。

以下是完整的代码

#include <iostream>
#include <map>
using namespace std;
class Node
{
private:
map<char, Node> mymap;
bool test;
public:
Node():test(false){}
bool getTest()
{
return test;
}
void setTest()
{
test = true;
}
map<char, Node>& getMap()
{
return mymap;
}
};
class A {
private:
Node* root;
public:
A()
{
root = new Node();
}
void insert(string word)
{
Node* crawler = root;
for (char ch : word)
{
if (crawler->getMap().find(ch) == crawler->getMap().end())
crawler->getMap()[ch] = Node();
crawler = &crawler->getMap()[ch];
}
crawler->setTest();
}
// This way if I access no valgring errors everything works fine
void worksFineWithPointer(string prefix)
{
Node* crawler = root;
cout << "worksFineWithPointer:" << endl;
for (char ch : prefix)
{
crawler = &crawler->getMap()[ch];
cout << crawler->getTest() << endl;
}
}
// Problematic Function but not able to find why it is wrong
void problem(string prefix)
{
Node crawler = *root;
cout << "Boolean Attribute changed to true when using objects instead of pointer:" << endl;
for (char ch : prefix)
{
crawler = crawler.getMap()[ch];
cout << crawler.getTest() << endl;
}
}
};
int main()
{
A a;
a.insert("test");
a.problem("test");
a.worksFineWithPointer("test");
return 0;
}

输出(当使用Efence编译和运行时,没有输出,因为它在打印前转储(:

Boolean Attribute changed to true when using objects instead of pointer:
1 <<<< how this changed to true
1 <<<< how this changed to true
1 <<<< how this changed to true
1 <<<< this was anyway true
WorksFineWithPointer:
0
0
0
1

我想我这里缺少了一些基本的C++概念,如果有人能解释有问题的代码语句的问题,那就太好了。

problem函数中,您正在制作Node副本,然后对其进行迭代。这与遍历指针不是一回事。

但我认为真正的问题是你的课堂设计

class Node
{
private:
map<char, Node> mymap;
// ...
};

在这一点上,Node是一个不完整的类型,因此您不能拥有该类型的映射。(从c++17,我认为不完全类型的vector是允许的(。对于map,我认为它的格式不正确,所以即使你的代码编译了,它也有UB,为什么它崩溃是无关紧要的。

不管怎样,我认为你最好有一张charNode*的地图。然后你的课看起来像这个

class Node
{
private:
map<char, Node*> mymap;
bool test;
public:
// ...   
map<char, Node*>& getMap()
{
return mymap;
}
};

然后你的功能变成

void worksFineWithPointer(string prefix)
{
Node* crawler = root;
cout << "worksFineWithPointer:" << endl;
for (char ch : prefix)
{
crawler = crawler->getMap()[ch];
cout << crawler->getTest() << endl;
}
}

void problem(string prefix) // no longer
{
Node crawler = *root;
cout << "Works fine with objects too :)" << endl;
for (char ch : prefix)
{
crawler = *crawler.getMap()[ch];
cout << crawler.getTest() << endl;
}
}

他们两个都应该工作得很好。

更好的是,把mymap变成map<char, std::unique_ptr<Node>>

最新更新