我正在尝试创建一个包装fopen()/ fclose()/ f *方法的类。我想将此方法用于其他目的,这就是我不想使用智能指针的原因。
问题是我不知道何时调用fclose()或其他'生命终结'功能。可以调用析构函数,但在此期间,FILE *被复制到另一个对象,例如通过复制构造函数。
我尝试编写'Reference Counter'类(它将是所有类的基类)但不幸的是我无法从构造函数/析构函数中调用纯虚方法。
这是我尝试过的:
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
}
答案 0 :(得分:2)
这里有两个解决方案,它们协同工作。
首先,不允许分配或复制您的"文件句柄"类。 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
正是您尝试实现的那种引用计数 - {{1}当最后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()
功能,我会更倾向于使它成为一个成员函数,以便它的用法是显式的,而不是在你不打算的时候自动发生。
答案 1 :(得分:1)
您可以使用带fclose
的共享指针作为删除器:
#include <cstdio>
#include <memory>
#include <stdexcept>
class File
{
private:
typedef std::shared_ptr<FILE> shared_file;
public:
// You might consider const char*
File(const std::string& FileName, const std::string& Mode)
: F(std::fopen(FileName.c_str(), Mode.c_str()), fclose)
{
if( ! F.get()) {
throw std::runtime_error("File Open Failure");
}
}
private:
shared_file F;
};
int main()
{
File File1("/tmp/test.txt", "r");
auto File2 = File1;
}