c++ - 当类的最后一个实例被破坏/覆盖时调用函数

标签 c++ reference-counting

我正在尝试创建一个包装 fopen()/fclose()/f* 方法的类。我想将此方法用于其他目的,这就是我不想使用智能指针的原因。

问题是我不知道何时调用 fclose() 或其他“生命终结”函数。可以调用析构函数,但同时 FILE * 被复制到另一个对象,例如通过复制构造函数。

我尝试编写“引用计数器”类(这将是所有类的基类)但不幸的是我无法从构造函数/析构函数调用纯虚方法。

这是我试过的:

class ReferenceCounter
{
    public:
        ReferenceCounter()
        {
            ReferenceCount = new unsigned int(0);
            AddRef();
        }
        ReferenceCounter(const ReferenceCounter & CopyFrom)
        {
            ReferenceCount = CopyFrom.ReferenceCount;
            AddRef();
        }
        ReferenceCounter & operator = (const ReferenceCounter & AssignFrom)
        {
            RemoveRef();
            ReferenceCount = AssignFrom.ReferenceCount;
            AddRef();

            return *this;
        }
        ~ReferenceCounter()
        {
            RemoveRef();
        }

        virtual void OnInit() = 0;
        virtual void OnDestruct() = 0;
    private:
        unsigned int * ReferenceCount;

        void AddRef()
        {
            if(++*ReferenceCount == 1)
                OnInit();
        }
        void RemoveRef()
        {
            if(--*ReferenceCount == 0)
            {
                OnDestruct();
                delete ReferenceCount;
            }
        }
};

也许有一种方法可以“覆盖”或“覆盖”一个类?

例子:

class File
{
    public:
        File(std::string FileName)
        {
            F = fopen(FileName.c_str(), ...);
        }
        ~File()
        {
            fclose(F);
        }
    private:
        FILE * F;
};

int main()
{
    File File1("a.txt");
    auto File2 = File1;

    //SegFault = fclose called twice for File1 and File2
}

最佳答案

这里有两个协同工作的解决方案。

首先,不允许分配或复制“文件句柄”类。1

class File
{
    // C++11 solution: use =delete
    public:
        File(File & const) = delete;
        File & operator=(File & const) = delete;

    // C++ < 11 solution: make them private and *don't implement them*:
    private:
        File(File & const);
        File & operator=(File & const);
};

其次,考虑只传递对单个 File 的引用目的。 (编译器不会再让您复制 File 对象,所以如果您不小心这样做,您会遇到编译器错误——这很好,因为它会帮助您确定需要修复的区域。)

如果建立单一所有权点太困难,请考虑使用 std::shared_ptr<File> 传递实例这正是您要实现的那种引用计数——File当最后一个 std::shared_ptr 时将被删除(因此它的析构函数被调用)本身就被破坏了。

auto file = std::make_shared(new File{"a.txt"});
auto file2 = file;
// file.use_count() and file2.use_count() are now both 2.
//
// When file2 is destructed this will drop to 1; when file is destructed this will
// drop to 0, and the File object will be deleted.

1 请注意,您可能可以使用 dup() 实现复制, 尽管赋值的语义可能有点棘手——赋值应该关闭现有句柄和 dup()正在分配的句柄?如果你执行 dup()功能 我更倾向于将其设为成员函数,这样它的用法就很明确,而不是在您可能不希望它这样做时自动发生。

关于c++ - 当类的最后一个实例被破坏/覆盖时调用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26044592/

相关文章:

c++ - 关于静态数据成员和成员函数定义的 extern 关键字,C++

c++ - Libtorrent 洪流->磁铁

c++ - itk::SmartPointer 的指针转换?

c++ - 引用计数垃圾收集

c++ - 原子递减比递增更昂贵吗?

c++ - 创建 5 个 1 到 20 之间唯一整数的数组的算法

c++ - 使用 C 或 C++ 检查互联网连接的最快方法是什么?

c++ - 如何在 C++ 中实现线程安全引用计数

objective-c - 为什么我的弱引用没有在强引用消失后立即被清除?

c# - 使用 C# 从 RLM 读取许可文件(C++ 到 C# 的翻译)