通过组合来实现引用计数可以吗?

发布于 2024-08-28 13:20:52 字数 1612 浏览 10 评论 0原文

最常见的可重用引用计数对象使用私有继承来实现重用。我不是私有继承的忠实粉丝,我很好奇这是否是一种可以接受的处理方式:

class ReferenceCounter {
    std::size_t * referenceCount;
public:
    ReferenceCounter()
        : referenceCount(NULL) {};
    ReferenceCounter(ReferenceCounter& other)
        : referenceCount(other.referenceCount) {
            if (!referenceCount) {
                referenceCount = new std::size_t(1);
                other.referenceCount = referenceCount;
            } else {
                ++(*referenceCount);
            }
    };
    ReferenceCounter& operator=(const ReferenceCounter& other) {
            ReferenceCounter temp(other);
            swap(temp);
            return *this;
    };
    void swap(ReferenceCounter& other) {
        std::swap(referenceCount, other.referenceCount);
    };
    ~ReferenceCounter() {
        if (referenceCount) {
            if (!*referenceCount)
                delete referenceCount;
            else
                --(*referenceCount);

        }
    };
    operator bool() const {
        return referenceCount && (*referenceCount != 0);
    };
};

class SomeClientClass {
    HANDLE someHandleThingy;
    ReferenceCounter objectsStillActive;
public:
    SomeClientClass() {
        someHandleThingy = RegCreateKeyEx(...);
    }
    ~SomeClientClass() {
        if (objectsStillActive)
            return;
        RegCloseKey(someHandleThingy);
    };
};

或者是否存在我没​​有看到的微妙问题?

编辑
我并不是超级关心这个特定的实现(它可能有错误——在生产代码中使用类似的东西之前我将花一些时间查看shared_ptr的内部结构)——我只是担心一般来说,有一个特定的原因可重用的引用计数好东西似乎总是使用继承而不是组合来实现。

Most common re-usable reference counted objects use private inheritance to implement re-use. I'm not a huge fan of private inheritance, and I'm curious if this is an acceptable way of handling things:

class ReferenceCounter {
    std::size_t * referenceCount;
public:
    ReferenceCounter()
        : referenceCount(NULL) {};
    ReferenceCounter(ReferenceCounter& other)
        : referenceCount(other.referenceCount) {
            if (!referenceCount) {
                referenceCount = new std::size_t(1);
                other.referenceCount = referenceCount;
            } else {
                ++(*referenceCount);
            }
    };
    ReferenceCounter& operator=(const ReferenceCounter& other) {
            ReferenceCounter temp(other);
            swap(temp);
            return *this;
    };
    void swap(ReferenceCounter& other) {
        std::swap(referenceCount, other.referenceCount);
    };
    ~ReferenceCounter() {
        if (referenceCount) {
            if (!*referenceCount)
                delete referenceCount;
            else
                --(*referenceCount);

        }
    };
    operator bool() const {
        return referenceCount && (*referenceCount != 0);
    };
};

class SomeClientClass {
    HANDLE someHandleThingy;
    ReferenceCounter objectsStillActive;
public:
    SomeClientClass() {
        someHandleThingy = RegCreateKeyEx(...);
    }
    ~SomeClientClass() {
        if (objectsStillActive)
            return;
        RegCloseKey(someHandleThingy);
    };
};

or are there subtle problems with this I'm not seeing?

EDIT
I'm not super duper concerned with this particular implementation (it probably has bugs -- I'm going to spend some time looking at shared_ptr's innards before using something like this in production code) -- I'm just concerned if in general there is a specific reason reusable reference counting goodies always seem to be implemented using inheritance rather than composition.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦在深巷 2024-09-04 13:20:52

复制句柄时一定要记住复制计数器。您可能不希望将操作系统类型传递到模板中,但我认为这里的安全性需要继承。 (不过,不是从 HANDLE 继承。)

HANDLE 也可能是一种特殊情况,因为它是 POD。本质上,您有一个除 T* 之外的类型的指针。

我看到了您希望在计数归零时发生除了删除之外的其他操作的动机。 smart_ptr 的改编可能会起作用,而且您可能离那不远了。

You have to remember to copy the counter when copying the handle. You might prefer not to pass operating system types into templates, but I think safety here requires inheritance. (Not inheritance from HANDLE, though.)

HANDLE might also be something of a special case because it's POD. Essentially you have a pointer of type besides T*.

I see the motivation that you want something besides delete to happen when the count goes to zero. An adaptation of smart_ptr would probably work, and you might not be that far from just that.

素染倾城色 2024-09-04 13:20:52

我不认为这有任何优点。引用计数仅对共享对象有意义。目标是节省堆分配和/或复制这些内容。事实上,您实现了某种复制计数器。但即使这样也没什么用,因为它不提供任何接口来查询计数器值。我可以建议重新访问 boost::intrusive

I don't think this has any merit. Reference counting only makes sense for shared objects. The goal is to save on heap allocations and/or copying of these among other things. You, in fact, implemented sort of copy counter. But even that is not useful since it does not provide any interface to query the counter value. Might I suggest revisiting boost::intrusive?

妞丶爷亲个 2024-09-04 13:20:52

事实上,您正在为 HANDLE 类之外的 HANDLE 实现引用计数...这非常接近 shared_ptr

使用组合来实现引用计数很好,但如果您的引用计数对象 ReferenceCounter 拥有类 HANDLE 实例会更好...使用起来更安全,并且重用成本更低,因为您只实现一次删除例程,而不是在所有构造函数(arg)中执行它。

使用私有继承的唯一有效原因是空基优化,所有其他情况都可以通过组合来处理,组合在耦合方面要好得多,因此他们不太可能有充分的理由这样做,更有可能的是,他们这样做是出于误导或懒惰。

You are in fact implementing reference counting for the HANDLE outside of the HANDLE class... which is damn close to a shared_ptr.

Using composition for implementing reference counting is fine, though it would be better if your reference counting object ReferenceCounter was to own the class HANDLE instance... Much safer in usage, and cheaper to reuse since you only implement the deletion routine once instead of doing it in all of your constructors (arg).

The single valid reason for using private inheritance is Empty Base Optimization, all the other cases can be dealt with composition which is much better in terms of coupling, so it's unlikely that they have good reasons to do so, more probably they did it out of misguidance or laziness.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文