嗨:)有谁能告诉我为什么下面的代码不起作用?程序在与if(children[word[letter_no] - 'A'] == nullptr)
对应的节点中的'B'
行崩溃。但是节点是创建的,当我尝试在构造函数中调用children[1]
时,它可以工作。但是当它在insert()
函数中被调用时,它并没有......
#include <memory> //shared_ptr
#include <string>
using namespace std;
const int ALPHABET = 26;
class Node {
public:
shared_ptr<Node> children[ALPHABET];
Node() { for (int i = 0; i < ALPHABET; ++i) children[i] = nullptr;}
void insert(const string &word, unsigned letter_no) {
if (letter_no < word.length()) {
if (children[word[letter_no] - 'A'] == nullptr)
children[word[letter_no] - 'A'] = make_shared<Node>();
children[word[letter_no] - 'A']->insert(word, letter_no+1);
}
}
};
int main() {
Node trie{};
trie.insert("ABC", 0);
return 0;
}
答案 0 :(得分:6)
启用编译器警告!
由于未指定的评估顺序,您有未定义的行为:
children[word[letter_no] - 'A']->insert(word, ++letter_no);
警告:无序修改和访问
letter_no
[-Wunsequenced]
此处您还有一个潜在的危险比较:
letter_no < word.length
警告:有符号和无符号整数表达式之间的比较
此外,您不应在现代C ++代码中使用new
和delete
。根据您需要的所有权语义,使用std::unique_ptr
或std::shared_ptr
。
来自评论:
Jecke :这都是真的,但没有一个是造成问题的原因。我简化了我的代码,因此在一个问题中它更具可读性。在我的原始代码中,我正在尝试使用shared_ptr,但结果是一样的。看,pastebin.com/MFZdrp22不能更好地工作(仍然是分段错误)
仔细看看这些内容:
if (letter_no < word.length())
{
if (children[word[letter_no] - 'A'] == nullptr)
{
children[word[letter_no] - 'A'] = make_shared<Node>();
}
++letter_no; // (0)
children[word[letter_no] - 'A']->insert(word, letter_no); // (1)
}
word
为"ABC"
。
word[letter_no] - 'A'
为0
。
在(0),您会增加letter_no
。
(1),word[letter_no] - 'A'
为1
。
children[1]
是nullptr
。的轰!强>
同样,编译器是你的朋友。使用-fsanitize=undefined
进行编译,您将收到以下错误消息:
runtime error: member call on null pointer of type 'Node'
runtime error: member access within null pointer of type 'Node'
答案 1 :(得分:2)
Vittorio已经回答了关于风格的几个词:
你只能有一种方法:
std::unique_ptr
然后您不需要覆盖,您可以使用 if (letter_no < word.length()) {
auto &child = children[word[letter_no] - 'A'];
if ( !child )
child = std::make_unique<Node>();
child->insert(word, ++letter_no);
}
并且您不需要在您的ctor中循环,并且如果您消除了代码重复:
f
这不仅会使您的代码更具可读性,而且会让您的问题消失
答案 2 :(得分:0)
Vittorio Romeo's answer是正确的。你应该经常清理你的警告。
但是为了给你一个完整的解释:
考虑1 st 递归时,letter_no
为0
。 word
包含'A'
,'B'
,'C'
和'\0'
。因此letter_no
会为'A'
编制索引。
验证letter_no
是word
letter_no < word.length()
的有效索引后,您递增 letter_no
:children[word[letter_no] - 'A']->insert(word, ++letter_no);
letter_no
在此行上作为1 st 操作递增,因此它实际上具有值1
,索引'B'
。然后用'A'
减去你的1
索引,这是一个未分配的元素。
就解决方案而言,您并不关心维护letter_no
的价值,因此请执行以下操作:children[word[letter_no] - 'A']->insert(word, letter_no + 1);