Delete[] 没有调用元素析构函数

Delete[] is not calling elements destructors

我已经开始使用 trie 实现字典。基本上,我有一个根节点,它有一个定义(指向 T 的指针,表示与键关联的 de 值)和子节点(指向包含指向 256 个节点的指针的数组的指针,每个字母一个)。检查定义:

template<typename T>
class DiccString {
        public:
                DiccString() : root(NULL);
                DiccString(const DiccString<T>&);
                ~DiccString() {delete root;}

                void define(const string& key, const T& value);
                bool isDefined(const string& key) const;
                const T& getDefinition(const string& key) const;
                T& getDefinition(const string& key);
                void remove(const string& key);
                const Set<string>& keys() const;

        private:

                struct Node{
                    Node** childs;
                    T* definition;
                    Node(){
                        std::cout << "Node has been created " << this << std::endl;
                        childs = new Node*[256];
                        definition = NULL;
                    }
                    ~Node(){
                        std::cout << "Node has been deleted " << this << std::endl;
                        delete definition;
                        delete [] childs;
                    }
                };

                Node* root;
};

所以如果我想用值 14 存储“John”(T 将是 int 所以),假设没有其他键,那么我会创建一个根,然后在根 ->childs[(int)'j'] 我会创建另一个节点 "nodeJ",然后是 nodeJ->childs[(int)'o'],依此类推,直到到达最后一个节点 "nodeN",它将包含值 (nodeN->definition = 14).

问题是我这样做的时候:

int main() {
    DiccString<int> d;
    d.define("john",20);
    d.define("jane",25);

    return 0;
}

然后我希望所有创建的节点都被销毁,但看看输出:

Node created 0x61fc20 // root
Node created 0x620860 // for letter 'j'
Node created 0x621090 // for letter 'o' (child of 'j' 0x620860)
Node created 0x6218c0 // for letter 'h' (child of 'o' 0x621090)
Node created 0x6220f0 // for letter 'n' (child of 'h' 0x6218c0), value: 20
Node created 0x622990 // for letter 'a' (child of 'j' 0x620860)
Node created 0x6231c0 // for letter 'n' (child of 'a' 0x622990)
Node created 0x6239f0 // for letter 'e' (child of 'n' 0x6231c0), value: 25
Node deleted 0x61fc20 // root

正在删除根目录。所以很明显,当在 Node 的析构函数中执行 delete [] childs 时,它并没有删除数组的所有元素,我确信它们存在:例如,在调用的情况下root 的析构函数(这是唯一实际被调用的析构函数),我评估了 childs[(int)'j'] 并且它肯定是 0x620860,所以我知道它应该在执行时调用这个元素的析构函数(至少)delete [] childs ,对吧?

我做错了什么?

打印输出只发生在 Node 个对象的销毁时,而不是 Node *。您可以使用调试器检查行为是否正确。

请注意,不要在 define() 中延迟分配,如果 constructor/destructor 之间具有对称性,可能会更清楚。还要确保正确处理释放时 DiccString 为空的情况。

childs 的类型是 Node**,它是一个指向指针的指针。你为它分配了一个 Node* 指针数组。

delete[] childs 删除此分配,即只删除指针的内存,而不是指针指向的对象。

我们看不到您实际分配 Node 的代码,但您必须以某种方式存储某处分配的 256 个 Node* 中的哪一个实际指向有效的 Node 对象.也许你通过用 NULL 指针标记指针来做到这一点?在那种情况下,您可能想做类似的事情:

for(int i=0; i<256; ++i) {
    delete childs[i];
}

我还应该注意,如果节点指针的数量是固定的,你应该使用静态数组,否则 std::vector