C++ C++;以RAII样式管理资源附件数组
下面是演示我试图解决的问题的幻想代码(请参阅注释C++ C++;以RAII样式管理资源附件数组,c++,raii,C++,Raii,下面是演示我试图解决的问题的幻想代码(请参阅注释//problem-);基本上,在做了一些可能抛出的事情之后,如何确保分离一堆资源句柄 #include <initializer_list> // from a C-style API extern int create_thingie(); // returns non-zero resource handle extern int create_widget(); // returns non-zero resource han
//problem-
);基本上,在做了一些可能抛出的事情之后,如何确保分离一堆资源句柄
#include <initializer_list>
// from a C-style API
extern int create_thingie(); // returns non-zero resource handle
extern int create_widget(); // returns non-zero resource handle
extern void attach_thingie(int widget_handle, int thingie_handle);
extern void detach_thingie(int widget_handle, int thingie_handle);
extern void delete_thingie(int handle); // deletes a thingie unless still attached
extern void delete_widget(int handle);
// RAII wrapper for thingies
class thingie {
int resource_handle;
public:
thingie() : resource_handle{create_thingie()} {}
thingie(const thingie&)=delete;
thingie& operator=(const thingie&)=delete;
thingie(thingie&& moved_from)
: resource_handle{moved_from.resource_handle}
{
moved_from.resource_handle = 0;
}
thingie& operator=(thingie&&)=delete;
~thingie() { delete_thingie(this->resource_handle); }
inline int get_handle() const
{
return this->resource_handle;
}
};
// RAII wrapper for widgets
// here identical to thingie, but not in my use-case
class widget {
int resource_handle;
public:
widget() : resource_handle{create_widget()} {}
widget(const widget&)=delete;
widget& operator=(const widget&)=delete;
widget(widget&& moved_from)
: resource_handle{moved_from.resource_handle}
{
moved_from.resource_handle = 0;
}
widget& operator=(widget&&)=delete;
~widget() { delete_widget(this->resource_handle); }
inline int get_handle() const
{
return this->resource_handle;
}
};
class foo {
widget underlying_widget;
public:
foo(std::initializer_list<thingie> thingies);
inline int get_underlying_handle() const
{
return this->underlying_widget.get_handle();
}
};
foo::foo(std::initializer_list<thingie> thingies)
{
for (thingie const& t : thingies)
attach_thingie(this->get_underlying_handle(), t.get_handle());
// do some potentially throwing things
// PROBLEM - thingies might not get detached, causing resource leak
for (thingie const& t : thingies)
detach_thingie(this->get_underlying_handle(), t.get_handle());
}
int main()
{
foo f1{thingie{}, thingie{}};
return 0;
}
#包括
//来自C风格的API
extern int create_thingie();//返回非零资源句柄
extern int create_widget();//返回非零资源句柄
外部无效附加内容(内部控件句柄,内部内容句柄);
extern void detach_thingie(int widget_handle,int thingie_handle);
extern void delete_thingie(int handle);//删除内容,除非仍然附加
extern void delete_小部件(int句柄);
//拉伊包装纸
阶级思想{
int-resource_句柄;
公众:
thingie():资源\u句柄{create\u thingie()}{}
thingie(const thingie&)=删除;
thingie&运算符=(const thingie&)=删除;
thingie(thingie&从中移动)
:resource\u handle{已从中移动\u。resource\u handle}
{
已从中移动\u。资源\u句柄=0;
}
thingie&operator=(thingie&&)=删除;
~thingie(){delete_thingie(this->resource_handle);}
内联int get_handle()常量
{
返回此->资源\u句柄;
}
};
//用于小部件的RAII包装器
//这里与thingie相同,但不在我的用例中
类小部件{
int-resource_句柄;
公众:
widget():资源\u句柄{create\u widget()}{}
小部件(常量小部件&)=删除;
小部件和运算符=(常量小部件&)=删除;
小部件(小部件和从中移动(&U)
:resource\u handle{已从中移动\u。resource\u handle}
{
已从中移动\u。资源\u句柄=0;
}
小部件&操作员=(小部件&&)=删除;
~widget(){delete_widget(this->resource_handle);}
内联int get_handle()常量
{
返回此->资源\u句柄;
}
};
福班{
小部件基础的小部件;
公众:
foo(std::初始值设定项\列表内容);
inline int get_底层_handle()常量
{
返回此->基础的_小部件。获取_句柄();
}
};
foo::foo(std::初始值设定项\u列表内容)
{
对于(thingie const&t:thingies)
附加内容(此->获取底层句柄(),t.获取句柄());
//做一些可能会扔东西的事情
//问题-内容可能无法分离,导致资源泄漏
对于(thingie const&t:thingies)
分离(这个->获取底层句柄(),t.获取句柄());
}
int main()
{
foo f1{thingie{},thingie{};
返回0;
}
我的第一个想法是在
foo::foo
中创建一个本地类来表示一个附件(或附件数组),它在构造函数中调用attach\u thingie
,在析构函数中调用detach\u thingie
,但我不知道如何以零开销的方式来实现这一点,而不是仅仅在foo::foo
之外的所有路由中运行分离for循环(即使用try
/catch(…)
)。闻起来像是过早优化。用一个挡块就行了。堆栈展开期间调用析构函数的速度不应快于catch块。如果有疑问,请测量。@Quimby我明白你的意思,可能更像是过早分解,只是因为我想太多了,避免为循环编写两个相同的分离。除非,有没有一种方法可以在没有两个相同循环的情况下使用catch块?但是循环并不完全相同,对吗?如果确实需要,可以将循环重构为一个方法,并使用函数指针调用正确的函数,或者使用一个简单的布尔参数进行附加/分离。因此,将逻辑保留在一个函数中。