问题描述
该对象称为:TF_Status-它是使用TF_NewStatus()函数创建的,并使用TF_DeleteStatus()函数删除的。
当我想将其与智能指针一起使用时,我将像这样初始化它:
std::unique_ptr<TF_Status,void(*)(TF_Status*)> status(TF_NewStatus(),TF_DeleteStatus);
但是,当我想将其用作类成员时,我不想在c'tor中创建对象,因为我必须先设置一些值。问题是这种智能指针没有默认值。
你们有什么解决办法吗?
解决方法
如果我理解正确,则需要这样的东西:
struct some_t
{
some_t()
: m_status(nullptr,TF_DeleteStatus)
{}
void later()
{
m_status.reset(TF_NewStatus());
}
std::unique_ptr<TF_Status,void(*)(TF_Status*)> m_status;
};
unique_ptr在构造时变为零指针。稍后,您可以创建TF_Status
对象。
您可以先实例化具有空指针的unique_ptr
,然后使用实际的TF_Status
重置该指针:
#include <iostream>
// TF_*
struct TF_Status {};
TF_Status* TF_NewStatus() { std::cout << "\tNew TF_Status\n" ; return new TF_Status(); }
void TF_DeleteStatus(TF_Status* s) { std::cout << "\tDelete TF_Status\n"; delete s; }
#include <memory>
class C
{
std::unique_ptr<TF_Status,decltype(TF_DeleteStatus)*> status;
public:
C() : status(nullptr,TF_DeleteStatus) {}
void acquire_status() {
status.reset(TF_NewStatus());
}
};
// test
int main()
{
std::cout << "About to instantiate a C\n";
C c;
std::cout << "done\n";
std::cout << "About to acquire_status\n";
c.acquire_status();
std::cout << "done\n";
}
输出
g++ -std=c++17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out About to instantiate a C done About to acquire_status New TF_Status done Delete TF_Status
给出
current_ptr
管理的指针*this
,按此顺序执行以下操作:
- 保存当前指针
old_ptr = current_ptr
的副本- 使用参数
current_ptr = ptr
覆盖当前指针- 如果旧指针为非空,则删除先前管理的对象
if(old_ptr) get_deleter()(old_ptr)
。
因此,即使您的智能指针在其上调用TF_Status
时,即使智能指针包含实际的reset()
,也可以保证安全。
(demo)
,我建议创建一个删除器类:
struct TF_Status;
void TF_DeleteStatus(TF_Status*);
struct TF_StatusDeleter {
void operator()(TF_Status* s) noexcept { TF_DeleteStatus(s); }
};
然后:
using TF_StatusPtr = std::unique_ptr<TF_Status,TF_StatusDeleter>;
这样TF_StatusPtr
可以被默认初始化(无需在构造函数中显式初始化此成员)和sizeof(TF_StatusPtr) == sizeof(TF_Status*)
。 std::unique_ptr
对删除程序使用空的基类优化,因此没有数据成员的TF_StatusDeleter
子对象占用0个字节。
std::unique_ptr<TF_Status,void(*)(TF_Status*)>
的大小是原来的两倍,因为每个实例都存储指向同一TF_DeleteStatus
函数的指针,这很浪费。