情况是一个参考计数的明智的指针在提高图书馆。

该问题的参照数,它无法处置的循环周期。我想知道如何去解决这C++。

请没有建议,如:"别让周期"或"使用weak_ptr".

编辑

我不喜欢的建议,说只使用一个weak_ptr因为显然如果你知道你将创造一个周期,然后你不会有问题。你还不知道你会有一个周期,在编制时间,如果你产生shared_ptrs期间,运行时间。

所以请你,自我删除的答案,使用weak_ptr在他们因为我特别要求不要有这样的答复...

有帮助吗?

解决方案

我还没有找到一个更好的方法绘制大UML图,并寻找出周期。

调试,我使用的一个实例计数器会的注册,这样的:

template <DWORD id>
class CDbgInstCount
{
public:
#ifdef _DEBUG
   CDbgInstCount()   { reghelper.Add(id, 1); }
   CDbgInstCount(CDbgInstCount const &) {  reghelper.Add(id, 1); }
   ~CDbgInstCount()  { reghelper.Add(id, -1); }
#else
#endif
};

我只是ned添加到这类问题,并有一个在注册表。

(ID,如果给出例如'XYZ!'将被转换成一串。不幸的是,你不能指定一个字符串不断为模板参数)

其他提示

shared_ptr 代表 所有权 的关系。同时 weak_ptr 代表 提高认识.有几个目的拥有彼此意味着你有问题的架构,这是解决改变中的一个或更多 自己的's入 意识到's(即, weak_ptr's)。

我不明白为什么暗示 weak_ptr 被认为无用的。

我理解你的烦恼是满口告诉使用weak_ptr打破循环的参考文献和自我几乎感觉不到愤怒的时候告诉我,环引用的都是不好的编程方式。

你问的具体如何做你点循环的参考。事实是,在一个复杂的项目有一些参考周期是间接的和难以发现。

答案是,你不应该作出虚假声明,离开你容易受到环的参考。我是认真的和我批评的一个非常受欢迎的做法-盲目地使用情况的一切。

你应该清楚,在你的设计指针是业主及其观察员。

对于所有者的使用情况

为观察员使用weak_ptr-所有的人,不只是那些你认为可以部分的一个周期。

如果按照这种做法再循环的引用也不会造成任何问题,你不需要担心他们。当然你会有大量的代码写的把所有这些weak_ptrs到shared_ptrs当你想要使用他们的提升是不是真的工作。

这是相当容易检测周期:

  • 设置一个数到一些相当大的数字,说1000(确切大小取决于你的应用程序)
  • 开始与pionter你有兴趣,并按照指针,从它
  • 每个指你跟着,递减计数
  • 如果计数降到零之前达到年底的指链,你有一个循环

不是,但是,非常有用的。它通常不能够解决cycvle问题ref计数的指针-那就是为什么替代垃圾垃圾方案等产生的清除被发明。

一个组合 boost::weak_ptrboost::shared_ptr 也许? 文可能感兴趣。

看看这篇文章 检测周期 在一个曲线图。

通用的解决方案找到一个周期可以在这里找到:

最好的算法来测试,如果一个链表具有周期

这个假设你知道结构中的对象清单,并且可以按照所有的指针包含在每个对象。

你可能需要一个垃圾收集技术,例如 标记和清扫.这个想法的这种算法是:

  1. 保留一个列有参考文献,所有的记忆区块的分配。
  2. 在某些时候你开始的垃圾收集器:
    1. 它首次标志着所有的街区,它仍然可以访问而使用的参考清单。
    2. 它通过该列表中删除的每个项目可能不被标记,这意味着这是不可访问了所以,它不是有用的。

因为你使用 shared_ptr 任何仍然存在的指针,你无法达到应该被认为是成员的周期。

执行情况

下面我将描述一个非常幼稚的例子如何实现的 sweep() 算法的一部分,但它将 reset() 所有剩余的指针上的收集器。

这个代码的商店 shared_ptr<Cycle_t> 指针。类 Collector 负责追踪所有的指针,并删除他们的时候 sweep() 是执行。

#include <vector>
#include <memory>

class Cycle_t;
typedef std::shared_ptr<Cycle_t> Ref_t;

// struct Cycle;
struct Cycle_t {
  Ref_t cycle;

  Cycle_t() {}
  Cycle_t(Ref_t cycle) : cycle(cycle) {}
};

struct collector {
  // Note this vector will grow endlessy.
  // You should find a way to reuse old links
  std::vector<std::weak_ptr<Cycle_t>> memory;

  // Allocate a shared pointer keeping
  // a weak ref on the memory vector:
  inline Ref_t add(Ref_t ref) {
    memory.emplace_back(ref);
    return ref;
  }
  inline Ref_t add(Cycle_t value) {
    Ref_t ref = std::make_shared<Cycle_t>(value);
    return add(ref);
  }
  inline Ref_t add() {
    Ref_t ref = std::make_shared<Cycle_t>();
    return add(ref);
  }

  void sweep() {
    // Run a sweep algorithm:
    for (auto& ref : memory) {
      // If the original shared_ptr still exists:
      if (auto ptr = ref.lock()) {
        // Reset each pointer contained within it:
        ptr->cycle.reset();

        // Doing this will trigger a deallocation cascade, since
        // the pointer it used to reference will now lose its
        // last reference and be deleted by the reference counting
        // system.
        //
        // The `ptr` pointer will not be deletd on the cascade
        // because we still have at least the current reference
        // to it.
      }
      // When we leave the loop `ptr` loses its last reference
      // and should be deleted.
    }
  }
};

然后你可以用这样的:

Collector collector;

int main() {
  // Build your shared pointers:
  {
    // Allocate them using the collector:
    Ref_t c1 = collector.add();
    Ref_t c2 = collector.add(c1);

    // Then create the cycle:
    c1.get()->cycle = c2;

    // A normal block with no cycles:
    Ref_t c3 = collector.add();
  }

  // In another scope:
  {
    // Note: if you run sweep an you still have an existing
    // reference to one of the pointers in the collector
    // you will lose it since it will be reset().
    collector.sweep();
  }
}

我测试了它与才有泄漏或"仍然不到"区块被列,所以它可能是工作的预期。

一些笔记本执行情况:

  1. 存储器矢量将增长不休,你应该使用 一些记忆分配技术 以确保它不会占用你所有的工作记忆。
  2. 一个可以争辩说,没有必要的使用 shared_ptr (那样工作的一个参考数GC)来实现这样的垃圾收集由于标记和清算法已经照顾的工作。
  3. 我没有实施标记()功能,因为它将复杂的例子,但这是可能的,我会解释它如下。

最后,如果你关心(2),这种实现是不是闻所未闻的。CPython(主要执行Python)不使用混合物的参数和标记和清除,但主要是用于 历史的原因.

执行《 mark() 功能:

来实现的 mark() 功能将需要作出一些修改:

它将需要添加一个 bool marked; 属性 Cycle_t, ,并利用它来检查是否的指标或没有。

你会需要编写 Collector::mark() 功能就是这样的:

void mark(Ref_t root) {
  root->marked = true;

  // For each other Ref_t stored on root:
  for (Ref_t& item : root) {
    mark(item);
  }
}

然后你应该修改 sweep() 功能删除的标记如果指标或别的 reset() 该指针:

void sweep() {
  // Run a sweep algorithm:
  for (auto& ref : memory) {
    // If it still exists:
    if (auto ptr = ref.lock()) {
      // And is marked:
      if (ptr->marked) {
        ptr->marked = false;
      } else {
        ptr->cycle.reset();
      }
    }
  }
}

它是一个冗长的解释,但是我希望它可以帮助别人。

回答的老问题,你可以尝试侵入性的指针可帮助计算有多少次的资源被提到。

#include <cstdlib>
#include <iostream>

#include <boost/intrusive_ptr.hpp>

class some_resource
{
    size_t m_counter;

public:
    some_resource(void) :
        m_counter(0)
    {
        std::cout << "Resource created" << std::endl;
    }

    ~some_resource(void)
    {
        std::cout << "Resource destroyed" << std::endl;
    }

    size_t refcnt(void)
    {
        return m_counter;
    }

    void ref(void)
    {
        m_counter++;
    }

    void unref(void)
    {
        m_counter--;
    }
};

void
intrusive_ptr_add_ref(some_resource* r)
{
    r->ref();
    std::cout << "Resource referenced: " << r->refcnt()
              << std::endl;
}

void
intrusive_ptr_release(some_resource* r)
{
    r->unref();
    std::cout << "Resource unreferenced: " << r->refcnt()
              << std::endl;
    if (r->refcnt() == 0)
        delete r;
}

int main(void)
{
    boost::intrusive_ptr<some_resource> r(new some_resource);
    boost::intrusive_ptr<some_resource> r2(r);

    std::cout << "Program exiting" << std::endl;

    return EXIT_SUCCESS;
}

这里的结果返回。

Resource created 
Resource referenced: 1 
Resource referenced: 2 
Program exiting 
Resource unreferenced: 1
Resource unreferenced: 0 
Resource destroyed
*** Program Exit ***

我知道你说"没有weak_ptr"但为什么不呢?有你的头weak_ptr到尾部和尾部的一个weak_ptr头将防止循环。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top