解决了由于循环引用而导致std :: shared_ptr泄漏的std :: vector

时间:2016-01-11 20:51:16

标签: pointers c++11 memory-leaks shared-ptr

我已经陷入困境:我编写了一个树形图结构,其中每一层都包含一个指向前一层(超类型)指针的向量和指向后续(子类型)层的指针。

你可以想象,这是一个循环参考:

[last] -(super)-> [current]
[current] -(sub)-> [last]

当我分配新的layer时,请确保将其移至current 当我最后重新分配给当前时,我再次移动它。

然而,这并没有解决泄漏,实际上我发现的唯一解决方案是使用原始指针。

这是一个缩小代码大部分的缩小示例:

struct layer
{
    std::unordered_set<std::string> words;
    std::vector<layer*> sub_classes;
    std::vector<layer*> super_classes;
}

实际迭代为wordnet senses,填充树形图。 执行hypernyms的函数(例如,单词的超类型)是:

void iterate_sense(
                        Synset * sense,
                        std::shared_ptr<layer> last,
                        graph & rhs,
                        int lexical
                      )
    {
        std::shared_ptr<layer> current;
        while (sense && last)
        {
            current = std::move(get_layer(sense));
            last->super_classes.push_back(current.get());
            current->sub_classes.push_back(last.get());
            if (sense->ptrlist)
            {
                iterate_sense(sense->nextss, 
                              last,
                              rhs, lexical);
            }
            last = std::move(current);
            sense = sense->ptrlist;
        }
    }

这些指针归另一个类graph所有。 当我在layer

中使用时
    std::vector<std::shared_ptr<layer>> sub_classes;
    std::vector<std::shared_ptr<layer>> super_classes;

Valgrind报告丢失了字节。

1

正确优雅解决此问题的方法是什么? 我假设使用原始指针不是最好的解决方案吗?

2

我是否正确假设所有者graph丢失的那一刻, 原始指针将变为无效? 这不是一个大问题,因为layers本身只存在于图表中。

3

我已经阅读了SO和谷歌,通过std::weak_ptrstd::shared_ptr的组合正确使用,但我不明白在这种情况下如何使用weak_ptr

1 个答案:

答案 0 :(得分:2)

1

智能指针,是关于所有者的船只。它说谁负责某个对象。语义基本上分为如下:

  • std::unique_ptr<>:一个函数/对象是对象的所有者和负责人。
  • std::shared_ptr<>:几个函数/对象是对象的所有者和负责人。
  • raw pointer:其他人是该对象的所有者并负责。

在您的情况下,我建议遵循语义:图层是其子图层的所有者。儿童不是其父母的所有者。

在此之后我会使用

std::vector<std::unique_ptr<layer>> sub_classes;
std::vector<layer*> super_classes;e

对于iterate_sense,我建议使用以下签名:

void iterate_sense(
                    Synset * sense,
                    layer* last,
                    graph & rhs,
                    int lexical
                  )

此函数未完全或部分拥有变量last中的对象。它只被授予有限的访问权限。

2

不确定graph拥有这些指针的方式。如果graph实际上是std::unique_ptr<>的所有者,则您只能在raw pointers中使用layers。这正是使用它的正确方法。

3

在某些情况下,可以使用std :: weak_ptr&lt;&gt;打破循环引用。我建议不要使用它们。如果您对数据结构进行了简洁的设计,通常很容易说出谁是对象的责任人/所有者。没有那么多的情况不明确。在这些不清楚的情况下,如果一个对象被多个其他对象管理/拥有,则需要std :: shared_ptr&lt;&gt;。在这些情况下,您可能需要访问一个您不知道它是否仍然存在的对象。在这种情况下,您可能希望使用std :: weak_ptr&lt;&gt;。