如何通过一组自定义对象指针正确处理垃圾收集并避免内存泄漏......?

时间:2015-10-21 14:11:54

标签: c++ pointers memory-management memory-leaks garbage-collection

所以我试图牢牢掌握如何编写对象和指针的集合,而不会导致内存泄漏...我想做这样的事情......

class StackTest
{
    public:
        StackTest() : m_id(-1), 
           m_name("")
        { };
        StackTest(const int id, 
           const std::string name) : m_id(id), 
           m_name(name)
        { };

        void SomeFunctionThatCanPreformTasksOnTHISStackTest();
    private:
        const int m_id;
        const std::string m_name;
}

class StackTestCollection
{
    public:
        void AddStackTest(const StackTest* test);

        void SomeFunctionThatCanPreformTasksOnAllStackTests();
    private:
        std::vector<StackTest*> m_stack_tests;
}

然后我给集合添加了函数AddStackTest(并为集合和单独的StackTest创建了处理函数的函数)......

void StackTestCollection::AddStackTest(const StackTest* test)
{
    m_stack_tests.push_back(test);
}

最后我的主要代码库......

// This scopes my_collection so that after the '}' my_collection should get deleted...
{
    StackTestCollection my_collection;
    my_collection.AddStackTest(new StackTest(0, "First Stack Test"));
    my_collection.AddStackTest(new StackTest(0, "Second Stack Test"));
    my_collection.AddStackTest(new StackTest(0, "Third Stack Test"));
}

现在我意识到我需要在存储在StackTestCollection中的StackTest指针上调用delete。我想我可以将它添加到StackTestCollection ....

~StackTestCollection()
{
    for(auto &test : m_stack_tests)
    {
        delete test;
    }
}

现在这让我问了几个问题......

1)这会导致程序在循环期间崩溃,因为我们正在删除堆中的数据,或者向量是否仍然稳定,因为堆栈中的指针仍然存在,但是是一个悬空指针... < / p>

2)我是否还需要对集合m_stack_tests向量运行删除?像这样......

delete m_stack_tests;

3)在我的主代码中,我创建了集合(StackTestCollection my_collection;),我的理解是我只需要用指针来控制垃圾....所以既然my_collection不是指针,我不会&# 39; t需要做一些事情......正确吗?

delete my_collection;

我想指出,此示例程序将在大型多线程服务器中运行,用户登录并分配自己的集合。 (因此每个用户在登录时都有自己的集合,并且在注销时也应该删除与用户相关的数据。)

另外,我没有使用C ++ 11,所以没有unique_ptr&#39; s。

4 个答案:

答案 0 :(得分:2)

1:只要没有其他内容(例如另一个线程)在删除之后尝试访问堆资源,这不会导致问题。

2:如果你使用new来创建它,你只需要删除一些东西。

3:你说你不需要删除my_collection但是假设必须删除每个指针都是错误的,请考虑以下代码:

void Foo(int* ptr)
{
    // do something
}

int i = 1234;
Foo(&i); // passing a pointer to i which is a stack based object

我建议使用智能指针来管理堆分配/解除分配,并避免使用new和delete。在您的情况下,您可以使用unique_ptr

的向量

答案 1 :(得分:0)

将vector定义为您的类型的共享指针的向量。这将允许共享指针的析构函数在从向量中删除值时销毁对象。

答案 2 :(得分:0)

你可以做两件事:

  1. 制作容器std::vector<StackTest> m_stack_tests;。无需内存处理。只需更改您的功能即可const StackTest&StackTest&&
  2. 制作容器std::vector<std::unique_ptr<StackTest>> m_stack_tests;。现在,有内存处理,但unique_ptr将为您处理一切,所以您不必担心它。
  3. 在这两种情况下,您都不必在任何地方写delete,这很棒。你写它的方式,你逐个delete向量中的每个元素......但你必须{{1}矢量本身。它不是delete

答案 3 :(得分:0)

通常,删除该内存 是安全的。

原因是指针是从外部源传入的,你不知道它们来自哪里(好吧,你,但是当你编写接口时,你应该假装你不要T)。调用者负责管理内存。这就是为什么std::vector在被破坏时不会为你释放内存的原因。

另一方面,你的班级不能安全地从指针的其他持有者那里删除它。这两个问题的解决方案是在AddStackTest函数中获取数据的副本,但这可能效率低下。

当然,如果你在上面的评论中说,

/* This class takes ownership of the objects passed in, and will delete
   them upon destruction.  */

...现在你已经改变了规则,如果不是他们想要的话,调用者必须采取措施来复制对象。

有多种方法可以实现这种破坏。像你这样的显式析构函数会起作用,因此使你的向量使用std::unique_ptr

顺便提一下,您的AddStackTest需要const StackTest*,但是您存储StackTest *,这似乎是错误的(编译器应警告您),除非您真的在那里制作副本。< / p>