标签: reference-counting

设计着色器类

由于我已经开始学习OpenGL,我想我也会编写一个小的C++框架(对我来说),以避免过度使用C-ish代码显然导致的恶心.:)由于我打算坚持使用Qt,因此框架使用了一些Qt类.

我真正需要的第一件事是使用着色器和程序的简单方法.这是我对着色器类的想法.

class Shader
{
public:
    //create a shader with no source code 
    explicit Shader(GLenum shaderType);
    //create a shader with source code and compile it
    Shader(GLenum shaderType, const QString& sourceCode);
    //create a shader from source file and compile it
    Shader(GLenum shaderType, QFile& sourceFile);
    ~Shader();

    //change the source code and recompile
    void Source(QFile& sourceFile);
    void Source(const QString& sourceCode);

    GLuint get() const; //get the handle

private:
    //common part for creation in different constructors
    void createShader(GLenum shaderType); 
    //compile
    void compile();

private: …
Run Code Online (Sandbox Code Playgroud)

c++ opengl qt reference-counting

5
推荐指数
1
解决办法
2494
查看次数

调度到对象拥有的队列是否会保留该对象?

假设我有一个简单的调用dispatch_async(self.queue, ^{ /* Empty */ }),其中self.queue是先前创建的队列.

self获得由块在这种情况下保留,因为没有self参考里面的块,但只作为一个参数dispatch_async()

reference-counting retain grand-central-dispatch objective-c-blocks

5
推荐指数
1
解决办法
504
查看次数

在调用FreeLibrary之前,如何确保释放Interface实例

我有一个dll导出一个返回接口的函数.

我为LoadLibrary,GetProcAddress和FreeLibrary函数创建了一个包装器,用于调用导出的函数.

TInterfaceGetter = class
private
...
public
  constructor Create;
  destructor Destroy; override;
  function GetInterface: IMyInterface;
end;
Run Code Online (Sandbox Code Playgroud)

当第一次调用GetInterface时,这个包装器延迟加载dll并缓存模块句柄和导出函数的proc地址.对FreeLibrary的调用发生在包装器的析构函数中.

除非客户端代码在释放包装器后挂起到接口引用上,否则一切都会很好地工作.当接口引用最终超出作用域时,对_IntfClear的结果调用会引发访问冲突,因为dll以及它正在使用的任何内存已经从客户端的内存空间中卸载.

我怎样才能优雅地处理这件事?完整的COM实现如何处理这种情况?

delphi memory-management reference-counting

5
推荐指数
1
解决办法
303
查看次数

将shared_ptr传递给lambda时的C ++内存管理

考虑以下C ++代码:

void f(std::function<void()> func) {
    func();
}

void g(std::shared_ptr<MyObject> myObjPtr) {
    myObjPtr->someMethod();
}

void h(std::shared_ptr<MyObject> myObjPtr) {
    f([=](){ g(myObjPtr); });
}
Run Code Online (Sandbox Code Playgroud)

是否有内存泄漏?

我的理解被myObjPtr复制到了lamba中,并增加了其引用计数。然后将其复制到g()参考计数再次增加的位置。当g()完成后,shared_ptr有递减引用计数。然后,后func()在执行f()shared_ptr有引用计数再次递减。所以我认为这段代码使引用计数保持平衡(两个增量和两个减量)。但是,我对shared_ptrlambda并不陌生,因此我的理解可能不正确。

c++ lambda reference-counting pass-by-value shared-ptr

5
推荐指数
1
解决办法
2731
查看次数

Swift中ARC溢出的可能性?

Swift使用"自动引用计数"来释放不再引用且因此不再需要的对象.Swift语言指南[1]陈述如下:

每次创建类的新实例时,ARC都会分配一块内存来存储有关该实例的信息.此内存保存有关与该实例关联的任何存储属性的值的信息.

我假设引用计数存储为整数.然后参考计数器会出现溢出吗?如果是这种情况,这会对我的程序产生什么影响,那些仍被其他人引用的对象是否会被解除分配?

例如:如果计数器是,例如,无符号的2字节整数,这将使对象的引用上限(虽然仍具有正确的引用计数)在130k左右.一旦达到该上限并再次引用该对象,这将使计数器增加1,再次将其设置为0.

[1] https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html

garbage-collection reference-counting automatic-ref-counting swift

5
推荐指数
1
解决办法
75
查看次数

原子decref实现之间的区别

我一直在研究原子引用计数的实现。

大多数操作在库之间是非常一致的,但是我发现“减少引用计数”操作令人吃惊。(请注意,通常,共享和弱decref之间的唯一区别是on_zero()被调用。下面将说明异常。)

如果还有其他根据C11 / C ++ 11模型实现的实现(MSVC做了什么?),而不是“我们使用seq_cst,因为我们没有更好的了解”类型,请随时对其进行编辑。

大多数示例最初都是C ++,但是在这里,我将它们重写为C,内联并按照>= 1约定进行了规范化:

#include <stdatomic.h>
#include <stddef.h>
typedef struct RefPtr RefPtr;
struct RefPtr {
    _Atomic(size_t) refcount;
};
// calls the destructor and/or calls free
// on a shared_ptr, this also calls decref on the implicit weak_ptr
void on_zero(RefPtr *);
Run Code Online (Sandbox Code Playgroud)

Boost intrusive_ptr示例openssl

void decref_boost_intrusive_docs(RefPtr *p) {
    if (atomic_fetch_sub_explicit(&p->refcount, 1, memory_order_release) == 1) {
        atomic_thread_fence(memory_order_acquire);
        on_zero(p);
    }
}
Run Code Online (Sandbox Code Playgroud)

可以对fetch_sub操作使用memory_order_acq_rel,但是当引用计数器尚未达到零时,这会导致不必要的“获取”操作,并且可能会导致性能下降。

但大多数其他工具( Boostlibstdc ++libc ++ …

c c++ atomic reference-counting memory-model

5
推荐指数
1
解决办法
119
查看次数

为什么Serde默认不支持Rc和Arc类型?

请解释一下Serderc功能

Rc<T>选择和的实现Arc<T>。序列化和反序列化这些类型不会保留身份,并且可能会导致相同数据的多个副本。在启用此功能之前,请确保这是您想要的。

序列化包含引用计数指针的数据结构将在每次在数据结构中引用指针时序列化指针内部值的副本。序列化不会尝试对这些重复数据进行重复数据删除。

反序列化包含引用计数指针的数据结构不会尝试删除对相同数据的重复引用。每个反序列化的指针都会以强计数 1 结束。

为什么存在此功能标志以及为什么它不是默认行为?这是什么意思

序列化和反序列化这些类型不会保留身份,并且可能会导致相同数据的多个副本

我知道它与Serde issues 194有关。该问题的最后一条消息说

如果您想确保不会意外地得到包含 rc 的派生 impl,请打开一个 Clippy 问题。

是否存在功能标志来捕获Rc结构的意外用法?

reference-counting rust serde

5
推荐指数
1
解决办法
1599
查看次数

拆分引用计数如何在无锁堆栈中工作?

我正在阅读 C++ concurrency in action 2。它为无锁堆栈引入了拆分引用计数。

一种可能的技术涉及对每个节点使用不是一个而是两个引用计数:内部计数和外部计数。这些值的总和就是对节点的引用总数。外部计数与指向节点的指针一起保存,每次读取指针时都会增加。当阅读器完成节点时,它会减少内部计数。读取指针的简单操作将在完成时使外部计数增加一,内部计数减一。

上面的短语解释了拆分引用计数的简要概念。听起来外部计数总是增加而内部计数总是减少。

当不再需要外部计数/指针配对时(节点不再能从多个线程可访问的位置访问),内部计数增加外部计数值减一,并丢弃外部计数器。一旦内部计数等于零,就没有对节点的未完成引用,可以安全地删除它。使用原子操作更新共享数据仍然很重要。现在让我们看看一个无锁堆栈的实现,它使用这种技术来确保只有在安全的情况下才回收节点。

但是在上面的短语中,当节点不再可访问时,内部计数应该增加外部计数的值减一。我对这个解释感到非常困惑。

(1) 使用内部和外部计数的确切目的是什么?

(2) 为什么它需要两个引用计数而不是一个?

编辑:我从书中添加了下面的示例代码。

template <typename T>
class lock_free_stack {
 private:
  struct node;
  struct counted_node_ptr {
    int external_count;
    node* ptr;
  };
  struct node {
    std::shared_ptr<T> data;
    std::atomic<int> internal_count;
    counted_node_ptr next;
    node(T const& data_)
        : data(std::make_shared<T>(data_)), internal_count(0) {}
  };
  std::atomic<counted_node_ptr> head;

  void increase_head_count(counted_node_ptr& old_counter) {
    counted_node_ptr new_counter;
    do {
      new_counter = old_counter;
      ++new_counter.external_count;
    } while (!head.compare_exchange_strong(old_counter, new_counter,
                                           std::memory_order_acquire,
                                           std::memory_order_relaxed));
    old_counter.external_count = new_counter.external_count;
  }

 public:
  ~lock_free_stack() {
    while (pop())
      ;
  } …
Run Code Online (Sandbox Code Playgroud)

c++ multithreading reference-counting lock-free

5
推荐指数
1
解决办法
87
查看次数

具有上下文管理器的生成器是反模式吗?

我想知道这样的代码:

def all_lines(filename):
    with open(filename) as infile:
        yield from infile
Run Code Online (Sandbox Code Playgroud)

上下文管理器的目的是对某种形式的状态(例如文件句柄)的生命周期进行显式控制。另一方面,生成器会保持其状态,直到耗尽或删除。

我确实知道这两种情况在实践中都有效。但我担心这是否是一个好主意。例如考虑这个:

def all_first_lines(filenames):
    return [next(all_lines(filename), None) for filename in filenames]
Run Code Online (Sandbox Code Playgroud)

我从来没有耗尽发电机的电量。相反,当生成器对象被删除时,它们的状态就会被破坏。这在像 CPython 这样的引用计数实现中工作得很好,但是垃圾收集实现呢?我实际上依赖引用计数器来管理状态,这是上下文管理器明确设计要避免的!

即使在 CPython 中,如果生成器是引用循环的一部分并且需要销毁垃圾收集器,那么构建案例也不应该太难。

总结一下:您是否认为避免生成器中的上下文管理器是明智的,例如将上面的代码重构为这样的代码?

def all_lines(filename):
    with open(filename) as infile:
        return infile.readlines()

def first_line(filename):
    with open(filename) as infile:
        return next(infile, None)

def all_first_lines(filenames):
    return [first_line(filename) for filename in filenames]
Run Code Online (Sandbox Code Playgroud)

python garbage-collection generator reference-counting

5
推荐指数
1
解决办法
299
查看次数

重载运算符删除,或者如何杀死一只猫?

我正在尝试重载operator delete,这样我就可以返回一个普通的指针,指向那些不希望使用智能指针的人,并且能够控制删除对象的时间.

我定义了一个由几个灵魂构造的类Cat,有一个重载的操作符删除,什么都不做,以及析构函数减少了灵魂的数量(并且还做了一些吹牛).当灵魂达到0时,析构函数调用global :: delete,然后cat死掉.

这听起来很简单,但不能按预期工作.这是代码:

class Cat {
public:
    Cat(string n): name(n), souls(9)
    { cout << "Myaou... " << name << " is born\n"; }

    ~Cat();
    void operator delete(void *p) { cout << "!!! operator delete called\n"; }
    void report()
    { cout << name << "'s here, " << souls << " souls to spend\n"; }

    friend ostream& operator<< (const ostream& o, const Cat& cat);
private:
    void kill();
    const string name;
    int souls;
};

Cat::~Cat()
{
    cout << "!!! …
Run Code Online (Sandbox Code Playgroud)

c++ operator-overloading reference-counting

4
推荐指数
2
解决办法
4214
查看次数