Home > database >  Ensure destroy function is called
Ensure destroy function is called

Time:03-28

Somebody use shared pointer to ensure that the aforementioned handle are destroyed when it's no longer needed.

In practice, the implementation of InitDemoStruct() DestroyStruct() struct DemoStruct are opaque to me.They are provided by others.

Although this code snippet works as expected, but it looks strange indeed:

It's commonly seen that a smart pointer points to a specific class or struct, e.g: std::shared_ptr<struct DemoSt> ptr2object; Recently, I saw such usage. Use smart pointer to pointer to a pointer of a specific class or struct, e.g:std::shared_ptr<struct DemoSt*> ptr2point_of_object;

UPDATED: There is an answer provided by nwp.

Here is the aforementioned code snippet:

#include <memory>
#include <iostream>

struct DemoStruct;
using DemoStructHandle = DemoStruct* ;

//In practice, the implementation of  `InitDemoStruct()` `DestroyStruct()` `struct DemoStruct` is opaque to me.
//They are provided by others.
struct DemoStruct{
};


void InitDemoStruct(DemoStructHandle* handle_ptr){
    *handle_ptr = new DemoStruct(); 
    //may do some other meaningful init in InitDemoStruct(); 
    };


void DestroyStruct(DemoStructHandle* handle_ptr){
    std::cout << "Destroy() is called" << std::endl;
    if(handle_ptr==nullptr){
        return;
    }

    delete *handle_ptr;
}

//I use shared pointer to ensure that the aforementioned handle is destroyed when it's no longer needed.
std::shared_ptr<DemoStructHandle> MakeDemoStructHandlePtr(void)
{  
    return std::shared_ptr<DemoStructHandle>(new DemoStructHandle(nullptr), [](DemoStructHandle* pHandle){
        DestroyStruct(pHandle);
        delete pHandle;});
}


int main()
{
    std::shared_ptr<DemoStructHandle> demo_class_handle_ptr = MakeDemoStructHandlePtr();
    InitDemoStruct(demo_class_handle_ptr.get());           
}

CodePudding user response:

This looks like a C wrapper around a C opaque handle.

In one file, it is strange, but when DemoStructHandle is the only complete type, you (intentionally) can't do much better.

CodePudding user response:

My answer:

class Wrarper_without_smartptr    
{
    public:
        Wrarper_without_smartptr(){
            InitDemoStruct(&handle);
        }

        Wrarper_without_smartptr(const Wrarper_without_smartptr&) = delete;
        Wrarper_without_smartptr operator=(const Wrarper_without_smartptr&)= delete;

        ~Wrarper_without_smartptr(){
            DestroyStruct(&handle);
        }

    private:
        DemoStructHandle handle;
};

CodePudding user response:

I assume your question is how to avoid the double indirection (pointer-to-pointer). You can do that like this:

std::shared_ptr<DemoStruct> MakeDemoStructPtr(/*void not required in C  */)
{  
    DemoStruct *pHandle;
    InitDemoStruct(&pHandle);
    return std::shared_ptr<DemoStruct>(pHandle,
        [](DemoStruct *pHandle){
            DestroyStruct(&pHandle);
        }
    );
}


int main()
{
    std::shared_ptr<DemoStruct> demo_class_handle_ptr = MakeDemoStructPtr();
}

The shared_ptr points to a DemoStruct instead of pointing to a DemoStructHandle.

If InitDemoStruct has more arguments, you can add the arguments to MakeDemoStructPtr

CodePudding user response:

I would use a shared_ptr like this:

struct DemoStructDeleter {
    void operator()(DemoStructHandle p) {
        DemoStructDestroy(&p);
    }
};

// in some function:
DemoStructHandle h;
InitDemoStruct(&h);
std::shared_ptr<DemoStruct> smartptr(h, DemoStructDeleter{});
// do something with smartptr

Note that it is not shared_ptr<DemoStructHandle>, because you do not want to have a smart pointer to the handle, but to the struct itself.

If you wrap this in a factory function, you need not have an explicit DemoStructDeleter, but can use a lambda function.

  • Related