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

时间:2010-04-15 01:26:49

标签: c++ reference-counting

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

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的内部) - 我只关心是否一般有一个特定的原因,可重复使用的引用计数好东西似乎总是使用继承而不是组合来实现。

3 个答案:

答案 0 :(得分:3)

复制手柄时必须记住复制计数器。您可能不希望将操作系统类型传递给模板,但我认为安全性需要继承。 (但不是从HANDLE继承。)

HANDLE也可能是特殊情况,因为它是POD。基本上你有T*之外的类型指针。

我看到除了delete之外你想要的东西在计数变为零时发生的动机。 smart_ptr的改编可能会奏效,而你可能也不会那么远。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

您实际上正在为HANDLE类之外的HANDLE实施引用计数...这非常靠近shared_ptr

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

使用私有继承的唯一正当理由是Empty Base Optimization,所有其他情况都可以处理组合,这在耦合方面要好得多,因此它们不太可能有充分理由这样做,更可能他们是出于误导或懒惰而做到的。