首页 文章

C清除动态分配对象指针的向量会导致异常吗?

提问于
浏览
2

我有一个名为 ClassA 的 class . 这个 ClassA 包含一个指向动态分配类 ClassB 的对象的向量 . ClassA 的析构函数如下所示:

ClassA::~ClassA() {
    for (vector<ClassB*>::iterator i = m_vActiveB.begin(), e = m_vActiveB.end(); i != e; ) {
        vector<ClassB*>::iterator tmp(i++);
        delete *tmp;
        m_vActiveB.erase(tmp);
    }
}

ClassC 中,我有一个 ClassA 对象的向量 . 我目前的情况是:如果我的 ClassC 向量中没有任何 ClassA 对象,那么一切正常 . 但是如果我有对象,然后在 ClassC 中对我的向量调用.erase(),则抛出异常 . 通过日志记录,我已经确定调用了 ClassA 析构函数(因为我的理解是 .erase() 会破坏每个向量成员),但是当循环开始时抛出异常 .

有谁知道这可能导致什么?谢谢!

5 回答

  • 2

    按照rule of zero并使用以下内容声明 m_vActiveB 成员向量:

    std::vector<ClassB> m_vActiveB;
    

    并让默认构造函数处理销毁 . 您也可以使用std::unique_ptr的向量,但是,就像您当前的解决方案一样,您不会利用数组中连续元素的自然效率 .

    在我的系统中,ClassB的对象本身需要从向量中不断地添加,删除和更新,以保持状态模型 .

    如果您的数据模型自然不是基于元素是连续的并且具有特定顺序的事实,那么 std::unordered_map ,关联容器(如 std::unordered_mapstd::unordered_set )可能是更好的解决方案,特别是如果您插入和删除不是驻留在矢量的末尾(而不是坐在中间) .

    您可能还想查看std::liststd::deque,它们分别提供快速插入和删除(也可以使迭代器无效) .

    我记得改变矢量内容使所有指针无效..这是正确的吗?

    如果调用std::vector::erase是,则所有迭代器都将失效(包括过去的结束迭代器) . 调用 erase 也会使删除对象的所有引用和指针无效(就像引用任何被销毁/解除分配的对象一样无效) .

  • -1

    来自文档:http://en.cppreference.com/w/cpp/container/vector/erase

    在擦除点或之后使迭代器和引用无效,包括end()迭代器 .

    这意味着您的 ie 迭代器都已失效 . 所以不要像你一样在循环中使用 erase

    还要考虑:

    • 使用智能指针,如 std::shared_ptr 而不是自己进行内存管理 .

    • 查找erase-remove,虽然它在这里不太有用,因为:

    • 你需要在你去的时候擦掉它们,当你甚至需要这样做的时候使用 m_vActiveB.clear() ,因为:

    • 这是析构函数, m_vActiveB 是成员 . 它自己打算清理它 .

  • 3

    使用 std::vector::erase 会导致擦除点处和之后的迭代器失效 . 因此,在第一次迭代之后,过去的结束迭代器 e 不再有效 .

    而是直接与每次迭代时从 std::vector::end 返回的迭代器进行比较 . 但是,在您的示例中,不需要删除任何内容,因为 m_vActiveB 是成员,并且在运行dtor后将自动销毁(但需要提供指向的数据的 delete ) .

    当擦除发生时,迭代器 i 也将变为无效,因为复制迭代器 i 并删除它仍然会导致从向量中删除相同的元素(擦除迭代器的副本没有帮助) .

    ClassA::~ClassA() {
        for (vector<ClassB*>::iterator i = m_vActiveB.begin(); i != m_vActiveB.end(); ++i) {
            //vector<ClassB*>::iterator tmp(i++); // Unnecessary
            delete *i;
            //m_vActiveB.erase(i); // Unnecessary as elements will be erased automatically.
        }
    }
    

    等效C 11代码:

    ClassA::~ClassA() {
        for (auto ptr : m_vActiveB) {
            delete ptr;
        }
    }
    

    更好的选择是使用C 11智能指针作为例如 std::unique_ptr ,可以自动处理分配和释放 .

    class ClassA {
        std::vector<std::unique_ptr<ClassB>> m_vActiveB; // No need for explicit destructor.
        /* ... */
    };
    

    或者,如果您不使用多态或有其他特定原因使用指针,那么为什么要使用指针呢?只需使用 std:vector<ClassB> 即可 .

  • 0

    您正在迭代它时从向量中删除元素 . 这使迭代器无效 .

    它应该是这样的:

    ClassA::~ClassA() 
    {
        for (auto e : m_vActiveB)
        {
            delete e;
        }
    }
    

    您不必清除向量,它在析构函数完成后无论如何都会被销毁 .

  • 1

    当您使用 vector::erase 时,它会使向量中的任何其他迭代器无效 .

    所以你不能使用“传统的”迭代器循环 .

    最简单的方法是Rakibul Hasan建议,只需删除所有指针然后 clear 向量 .

相关问题