在这种情况下如何使用智能指针
How to use smart pointer in this situation
我想在以下情况下使用智能指针:
SOME_STRUCT* ptr = new SOME_STRUCT;
ptr->SOME_MEMBER = new BYTE[100];
CallSomeAPI(ptr);
现在 API 可能 return 出错或成功通过,但在这两种情况下我都想删除对象,一种方法是在错误退出和正常退出期间编写删除语句.
但是我如何为这些指针使用智能指针呢?
我所说的智能指针是指 unique_ptr、shared_ptr 等,无论哪个都可以工作!
谢谢!
您可以为 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>;
我建议将 new SOME_STRUCT;
更改为 new SOME_STRUCT{};
以默认将 SOME_MEMBER
初始化为 nullptr
。
我对这个解决方案不是 100% 满意,所以也许可以查看 scope_guard
或为您的结构编写一个包装器 class。
我假设您无法修改 SMOE_STRUCT
以向其添加析构函数。这给您留下了两个选择:自定义删除器和封装。
首先,您可以创建一个自定义删除器以用于 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());
如果您发现与您问题中描述的情况不同,共享所有权比独占所有权更适合您,您也可以使用带有 shared_ptr
的删除器,如下所示:
std::shared_ptr<SOME_STRUCT> ptr{new SOME_STRUCT, SOME_STRUCT_Deleter{}};
ptr->SOME_MEMBER = new BYTE[100];
CallSomeAPI(ptr.get());
我认为更可取的第二个选项是包装 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);
您甚至可以通过 SOME_STRUCT_plus_plus
从 SOME_STRUCT
派生而不是聚合它来 "wrap" 它,这样您就可以直接访问成员而无需通过 s
.同时,如果有人将 SOME_STRUCT_plus_plus*
转换为 SOME_STRUCT*
,然后在其上调用 delete
,则可能会导致内存泄漏。
这里好像可以全部入栈:
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());
我想在以下情况下使用智能指针:
SOME_STRUCT* ptr = new SOME_STRUCT;
ptr->SOME_MEMBER = new BYTE[100];
CallSomeAPI(ptr);
现在 API 可能 return 出错或成功通过,但在这两种情况下我都想删除对象,一种方法是在错误退出和正常退出期间编写删除语句.
但是我如何为这些指针使用智能指针呢? 我所说的智能指针是指 unique_ptr、shared_ptr 等,无论哪个都可以工作!
谢谢!
您可以为 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>;
我建议将 new SOME_STRUCT;
更改为 new SOME_STRUCT{};
以默认将 SOME_MEMBER
初始化为 nullptr
。
我对这个解决方案不是 100% 满意,所以也许可以查看 scope_guard
或为您的结构编写一个包装器 class。
我假设您无法修改 SMOE_STRUCT
以向其添加析构函数。这给您留下了两个选择:自定义删除器和封装。
首先,您可以创建一个自定义删除器以用于 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());
如果您发现与您问题中描述的情况不同,共享所有权比独占所有权更适合您,您也可以使用带有 shared_ptr
的删除器,如下所示:
std::shared_ptr<SOME_STRUCT> ptr{new SOME_STRUCT, SOME_STRUCT_Deleter{}};
ptr->SOME_MEMBER = new BYTE[100];
CallSomeAPI(ptr.get());
我认为更可取的第二个选项是包装 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);
您甚至可以通过 SOME_STRUCT_plus_plus
从 SOME_STRUCT
派生而不是聚合它来 "wrap" 它,这样您就可以直接访问成员而无需通过 s
.同时,如果有人将 SOME_STRUCT_plus_plus*
转换为 SOME_STRUCT*
,然后在其上调用 delete
,则可能会导致内存泄漏。
这里好像可以全部入栈:
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());