【问题标题】:Delete[] is not calling elements destructorsDelete[] 不调用元素析构函数
【发布时间】:2017-02-15 23:29:13
【问题描述】:

我已经开始使用 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 所以),假设没有其他密钥,那么我将创建一个根,然后在 root->childs[(int)'j'] 创建另一个节点“nodeJ”,然后创建 nodeJ->childs[(int)'o'],依此类推,直到到达最后一个节点“nodeN”,其中将包含值 ( nodeN-&gt;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时调用这个元素的析构函数,对吧?

我做错了什么?

【问题讨论】:

    标签: c++ arrays destructor trie


    【解决方案1】:

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

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

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

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

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

    【讨论】:

    • 哦,我明白了.. 我明天会尝试解决它。感谢您的回答!
    【解决方案2】:

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

    请注意,与其在define() 中延迟分配,不如在构造函数/析构函数之间具有对称性可能会更清楚。释放时DiccString为空的情况也一定要正确处理。

    【讨论】:

    • 构造函数和析构函数之间具有相似性是什么意思? (谢谢你的回答)
    • DiccString() 应该有分配,~DiccString() 应该有匹配的解除分配。
    猜你喜欢
    • 2014-11-22
    • 2013-06-25
    • 2018-06-02
    • 1970-01-01
    • 1970-01-01
    • 2021-09-24
    • 2016-09-06
    • 2016-03-12
    • 2011-01-12
    相关资源
    最近更新 更多