Reputation: 162
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
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
Reputation: 171127
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
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