Wrapping around old C Structures with smart pointers in C++11 and auto-freeing them

荒凉一梦 提交于 2019-12-02 01:36:39

I know how to solve this problem for unique ownership, using unique_ptr's nifty feature where its managed type becomes Deleter::pointer, instead of T*, if the former type exists.

Assuming you don't have the definition of Synset, or whatever type SynsetPtr points to, the problem with using a shared_ptr is that it doesn't have the same facility of switching the managed type, and if you create a shared_ptr<SynsetPtr>, the constructor will expect a SynsetPtr*, but your C API functions don't return that type. And I don't know for sure whether using shared_ptr<remove_pointer<SynsetPtr>::type> will compile if you don't have the definition of the type that dereferencing a SynsetPtr yields.

This might work, but I'm not sure.

std::shared_ptr<std::remove_pointer<SynsetPtr>::type>
make_findtheinfo_ds(char *searchstr, int pos, int ptr_type, int sense_num)
{
    return std::shared_ptr<std::remove_pointer<SynsetPtr>::type>
               (findtheinfo_ds(searchstr, pos, ptr_type, sense_num),
                free_syns);
}

std::shared_ptr<std::remove_pointer<SynsetPtr>::type>
make_traceptrs_ds(SynsetPtr synptr, int ptr_type, int pos, int depth)
{
    return std::shared_ptr<std::remove_pointer<SynsetPtr>::type>
               (traceptrs_ds(synptr, ptr_type, pos, depth),
                free_synset);
}

Going the unique ownership route, I'd make a couple of factory functions that return unique_ptrs managing SynsetPtrs.

We need 2 separate deleters for the different kinds of SynsetPtrs

struct sense_list_del
{
    using pointer = SynsetPtr;
    void operator()(SynsetPtr p)
    {
        free_syns(p);
    }
};

struct linked_list_del
{
    using pointer = SynsetPtr;
    void operator()(SynsetPtr p)
    {
        free_synset(p);
    }
};

std::unique_ptr<SynsetPtr, sense_list_del>
make_findtheinfo_ds(char *searchstr, int pos, int ptr_type, int sense_num)
{
    return std::unique_ptr<SynsetPtr, sense_list_del>
               (findtheinfo_ds(searchstr, pos, ptr_type, sense_num));
}

std::unique_ptr<SynsetPtr, linked_list_del>
make_traceptrs_ds(SynsetPtr synptr, int ptr_type, int pos, int depth)
{
    return std::unique_ptr<SynsetPtr, linked_list_del>
               (traceptrs_ds(synptr, ptr_type, pos, depth));
}

You can use std::shared_ptr for this purpose, as you can provide the deleter to use to free the pointer.

std::shared_ptr<Synset> findTheInfo(...) {
    std::shared_ptr<Synset> sp(findtheinfo(...), free_syns);
    return sp;
}
std::shared_ptr<Synset> tracePtrs(...) {
    std::shared_ptr<Synset> sp(traceptrs(...), free_synset);
    return sp;
}

Now, if they really represent different things, you might want to spend a bit more effort and provide two types that wrap each use and provide the appropriate interface. Does it make sense to treat both as the same type when transversing a list and a tree might be completely different?

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!