【问题标题】:using std::tr1::shared_ptr as an internal mechanism for reference counting使用 std::tr1::shared_ptr 作为引用计数的内部机制
【发布时间】:2012-01-10 07:07:03
【问题描述】:

出于引用计数的目的,在下面的示例代码中使用 std::tr1::shared_ptr 是否安全且正确? (这只是一个特定的示例,该类可以包含其他任何内容(void*)而不是 FILE*)

class File
{
public:
    File(const char* path, const char* mode) :
        _refcount(new int(0))
    {
        this->_file = fopen(path, mode);
    }

    ~File()
    {
        if (this->_refcount.unique())
        {
            if (this->_file != NULL)
            {
                fclose(this->_file);
            }
        }
    }

    int write(void* buff, size_t size)
    {
        fwrite(buff, size, 1, this->_file);
    }

private:
    FILE* _file;
    std::tr1::shared_ptr<int> _refcount;
};

【问题讨论】:

  • 安全在什么意义上?内存安全吗?线程安全吗?
  • @KennyTM 是的,内存安全和线程安全,以及从任何其他角度来看。 (我想它不是线程安全的,也许你可以解释一下如何修复它)
  • 我没有说它不是线程安全的 ;) 但我会像 James 的解决方案一样写这个,而不是显式的 ref-counter。
  • 乍一看,我在您的示例中没有看到任何明显的数据竞争。如果unique() 返回true,那么拥有FILE* 的唯一实例就是被销毁的实例,因此没有其他实例可以复制,因此unique() 无法再次不再为true。当然,通过多个线程的单个FILE* 执行 I/O 只能以眼泪收场。 /cc @KennyTM

标签: c++ shared-ptr smart-pointers tr1 reference-counting


【解决方案1】:

考虑使用带有自定义删除器的shared_ptr&lt;FILE&gt;

struct fclose_deleter
{
    void operator()(FILE* f)
    {
        if (f)
        {
            std::fclose(f);
        }
    }
};

那么,你的File 类就简单多了(而且更正确):

class File
{
public:
    File(const char* path, const char* mode)
        : _file(std::fopen(path, mode), fclose_deleter())
    {
    }

    int write(void const* buff, size_t size)
    {
        // You'll want to verify that _file.get() is valid, or you'll want to
        // throw in the constructor if the call to 'std::fopen()' fails.
        std::fwrite(buff, size, 1, _file.get());
    }

private:
    std::tr1::shared_ptr<FILE> _file;
};

【讨论】:

  • 类可以包含任何数据(void*),文件只是一个例子
  • 此技术适用于任何需要清理的引用计数对象。
  • 这个和其他有趣的shared_ptr 技术可以在这里找到:boost.org/doc/libs/1_48_0/libs/smart_ptr/sp_techniques.html :)
  • @JamesMcNellis 这种方法有两个缺点: 1. 在课堂上的任何地方我都必须使用 _file.get(); 2.如果类有更多指针成员,我必须创建其他shared_ptr。你能指出我的原始版本有什么优势吗?
  • 为什么要创建另一个shared_ptr?创建一个包含所有“共享”成员的私有 Context 类型。至于必须使用_file.get(),如果这真的困扰您,请添加FILE* file() const { return _file.get(); }。至于优点,是的:它更简单,更容易理解所有权和资源管理,而且更难搞砸。
猜你喜欢
  • 2011-08-01
  • 2010-10-03
  • 1970-01-01
  • 1970-01-01
  • 2012-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-29
相关资源
最近更新 更多