stng
stng

Reputation: 162

How to use smart pointer in this situation

I want to use smart pointer in the following situation:

   SOME_STRUCT* ptr = new SOME_STRUCT;
   ptr->SOME_MEMBER = new BYTE[100];
   CallSomeAPI(ptr);

now the API can either return error or pass successfully but in both those cases i want to delete the object , one way can be to write delete statement during error exit and during normal exit.

But how can i use a smart pointer for these pointers ? By smart pointers i mean unique_ptr, shared_ptr , etc. whichever can work !

Thanks!

Upvotes: 5

Views: 173

Answers (3)

Jarod42
Jarod42

Reputation: 217438

Here, it seems that all can be on the stack:

SOME_STRUCT ptr;         // or auto ptr = std::make_unique<SOME_STRUCT>();
BYTE bytes[100];         // or std::vector<BYTE> bytes(100);
ptr.SOME_MEMBER = bytes; // or ptr->SOME_MEMBER = bytes.data();
CallSomeAPI(&ptr);       // or CallSomeAPI(ptr.get());

Upvotes: 1

I assume you cannot modify SMOE_STRUCT to add a destructor to it. This leaves you with two options: a custom deleter, and encapsulation.

First, you could create a custom deleter for use with std::unique_ptr:

struct SOME_STRUCT_Deleter
{
  void operator() (SOME_STRUCT *p) const
  {
    delete[] p->SOME_MEMBER;
    delete p;
  }
};

std::unique_ptr<SOME_STRUCT, SOME_STRUCT_Deleter> ptr{new SOME_STRUCT};
ptr->SOME_MEMBER = new BYTE[100];
CallSomeAPI(ptr.get());

If you find that, unlike the situation described in your question, shared ownership would suit you better than exclusive one, you can use the deleter with a shared_ptr as well, like this:

std::shared_ptr<SOME_STRUCT> ptr{new SOME_STRUCT, SOME_STRUCT_Deleter{}};
ptr->SOME_MEMBER = new BYTE[100];
CallSomeAPI(ptr.get());

A second option, which I find preferable, is to wrap SOME_STRUCT:

struct SOME_STRUCT_plus_plus
{
  SOME_STRUCT s;
  ~SOME_STRUCT_plus_plus()
  {
    delete[] s.SOME_MEMBER;
  }

  SOME_STRUCT_plus_plus()
  {
    s.SOME_MEMBER = new BYTE[100];
  }
};

std::unique_ptr<SOME_STRUCT_plus_plus> ptr{new SOME_STRUCT_plus_plus};
CallSomeAPI(&ptr->s);

You could even "wrap" it by making SOME_STRUCT_plus_plus derive from SOME_STRUCT instead of aggregating it, which would give you direct access to members without the need to go through s. At the same time, it could lead to memory leaks if someone cast SOME_STRUCT_plus_plus* to SOME_STRUCT* and then called delete on it.

Upvotes: 2

Pubby
Pubby

Reputation: 53047

You can write a custom deleter for unique_ptr.

struct my_deleter {
    void operator()(SOME_STURCT* ptr) const {
        delete[] ptr->SOME_MEMBER;
        delete ptr;
    }
};

using my_ptr = std::unique_ptr<SOME_STRUCT, my_deleter>;

and I would suggest changing new SOME_STRUCT; to new SOME_STRUCT{}; to default initialize SOME_MEMBER to nullptr.

I am not 100% happy with this solution, so perhaps look into scope_guard or writing a wrapper class for your struct.

Upvotes: 3

Related Questions