使用共享指针与在另一个函数中分配的内存

时间:2013-12-19 15:12:48

标签: c++ c++11

我在工作中有一些遗留代码,它接受一个双指针并为其分配内存。一个缩短的例子看起来像这样:

struct LegacyObj
{
    int a;
    double b;
};

void LegacyAllocator(LegacyObj** ppObj)
{
    *ppObj = (LegacyObj*)malloc(sizeof(LegacyObj));
}

void LegacyDeleter(LegacyObj** ppObj)
{
    free(*ppObj);
}

实际的LegacyAllocator函数大约是100行,并且通过创建LegacyObj指针的链接列表来混合文件读取,并且我现在无法通过重写来逃避。但是,我想使这个函数的使用更安全一点,避免因异常& tc而导致的任何内存泄漏。我想出的第一个解决方案是将它包装在一个类中并处理调用ctor / dtor中的遗留函数。

class RAIIWrapper
{
public:
    RAIIWrapper()
        :obj{nullptr}
    {
        ::LegacyAllocator(&obj);
    }
    RAIIWrapper(RAIIWrapper&& that)
        : obj{ that.obj}
    {
        that.obj = nullptr;
    }
    RAIIWrapper& operator=(RAIIWrapper&& that)
    {
        RAIIWrapper copy{std::move(that)};
        std::swap(obj, copy.obj);
        return *this;
    }
    ~RAIIWrapper ()
    {
        ::LegacyDeleter(&obj);
    }

private:
    LegacyObj* obj;
};

但我很好奇 - 有没有办法使用std::shared_ptrstd::unique_ptr执行此操作?我不能在没有将原始指针传递给LegacyAllocator的情况下提出解决方案。

3 个答案:

答案 0 :(得分:3)

是的,您可以使用std::unique_ptrstd::shared_ptr的自定义删除工具,例如:

struct Deleter {
  void operator()(LegacyObj *p) const {
    LegacyDeleter(&p);
  }
};

std::unique_ptr<LegacyObj, Deleter> MakeLegacyObj() {
  LegacyObj *p = 0;
  LegacyAllocator(&p);
  return std::unique_ptr<LegacyObj, Deleter>(p);
}

std::unique_ptr<LegacyObj, Deleter> p = MakeLegacyObj();

而且,正如@Dave正确指出的那样,这也适用于shared_ptr

std::shared_ptr<LegacyObj> p = MakeLegacyObj();

答案 1 :(得分:0)

您可以使用unique_ptr删除内存,但由于内存是使用Deleter而不是malloc分配的,因此您必须提供自定义new类。

更好的是,更改分配代码以改为使用new并使用unique_ptr。如果你走这条路,你可以让分配器返回unique_ptr而不是指向内存的指针。

假设您需要提供自己的自定义删除工具,可以采用以下方法:

template <typename T>
class MallocDeleter
{
public:
  void operator() (T* obj) const
  {
    LegacyDeleter (*obj);
  }
};

typedef std::unique_ptr <LegacyObj, MallocDeleter <LegacyObj>> unique_legacy_ptr;

你也可以提供一个make_unique_legacy类型的函数,通过调用LegacyAllocator进行分配,而不必自己初始化unique_ptr

答案 2 :(得分:0)

您可以为此unique_ptr创建工厂函数:

typedef void(* LegacyDeleterType)(LegacyObj*);
typedef std::unique_ptr<LegacyObj,LegacyDeleterType> UniqueLegacyPtr;

UniqueLegacyPtr makeUniqueLegacyObj()
{
    LegacyObj * p = nullptr;
    LegacyAllocator( &p );
    return UniqueLegacyPtr( p, [](LegacyObj*p){ LegacyDeleter(&p); } );
}

您现在可以使用它来创建unique_ptr,并且您还可以分配给shared_ptr,它们会在构造时自动捕获自定义删除器:

int main()
{
    auto unique = makeUniqueLegacyObj();
    std::shared_ptr<LegacyObj> shared = makeUniqueLegacyObj();
}