如何检测周期时使用情况
-
13-09-2019 - |
题
情况是一个参考计数的明智的指针在提高图书馆。
该问题的参照数,它无法处置的循环周期。我想知道如何去解决这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_ptr
和 boost::shared_ptr
也许? 此 文可能感兴趣。
看看这篇文章 检测周期 在一个曲线图。
你可能需要一个垃圾收集技术,例如 标记和清扫.这个想法的这种算法是:
- 保留一个列有参考文献,所有的记忆区块的分配。
- 在某些时候你开始的垃圾收集器:
- 它首次标志着所有的街区,它仍然可以访问而使用的参考清单。
- 它通过该列表中删除的每个项目可能不被标记,这意味着这是不可访问了所以,它不是有用的。
因为你使用 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();
}
}
我测试了它与才有泄漏或"仍然不到"区块被列,所以它可能是工作的预期。
一些笔记本执行情况:
- 存储器矢量将增长不休,你应该使用 一些记忆分配技术 以确保它不会占用你所有的工作记忆。
- 一个可以争辩说,没有必要的使用
shared_ptr
(那样工作的一个参考数GC)来实现这样的垃圾收集由于标记和清算法已经照顾的工作。 - 我没有实施标记()功能,因为它将复杂的例子,但这是可能的,我会解释它如下。
最后,如果你关心(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头将防止循环。