自动毁坏 [英] Auto destruct

查看:43
本文介绍了自动毁坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



以MSWindows为例:


在MSWindows上,有一个叫做系统注册表的东西,真的是

大数据库,包含操作系统的所有设置。与注册表一起使用

的API。我要关注的两个是:


RegOpenKeyEx

RegCloseKey


现在,这里有一些代码:


int main()

{

HKEY hkey;


RegOpenKeyEx(& hkey);


... //一些东西


RegCloseKey(hkey);

}

这里唯一的问题是如果在某些东西期间抛出异常,

那么密钥永远不会被关闭。这是我的第一个解决方案:


class HKEYe

{

public:


HKEY hkey;

bool to_be_closed;


HKEYe():to_be_closed(false){}


~ HKEYe()

{

if(to_be_closed)

{

RegCloseKey(hkey);

}

}


运营商HKEY&(){return hkey; } $ / $
运算符const HKEY&()const {return hkey; }

HKEY * operator&(){return& hkey; }

const HKEY * operator&()const {return& hkey; }

};


int main()

{

HKEYe hkey;


RegOpenKeyEx(& hkey);


hkey.to_be_closed = true;


// ..一些东西


RegCloseKey(hkey);

hkey.to_be_closed = false;


}

现在如果抛出异常,那么密钥就会关闭。


无论如何,我的下一个想法就是制作一个模板。这之前是否已经完成了?b $ b?无论如何,这是我的第一次尝试:

模板< class T>

类AutoDestructive

{

公开:


T t;

bool to_be_auto_destructed;


AutoDestructive():t(),to_be_auto_destructed( false){}

模板< class A> AutoDestructive(A a):t(a),to_be_auto_destructed

(false){}

模板< class A> AutoDestructive(const A a):t(a),

to_be_auto_destructed(false){}

template< class A,class B> AutoDestructive(A a,B b):t(a,b),

to_be_auto_destructed(false){}

模板< A类,B类,C类> AutoDestructive(A a,B b,C c):t

(a,b,c),to_be_auto_destructed(false){}

虚拟~AutoDestructive ()= 0;


运算符T&(){return t; } $ / $
运算符const T&()const {return t; }

T * operator&(){return& t; }

const T * operator&()const {return& t; }

};


类AutoDestructive_HKEY:public AutoDestructive< HKEY>

{

public:


~AutoDestructive_HKEY()

{

if(to_be_auto_destructed)RegCloseKey(t);

}

};


int main()

{

AutoDestructive_HKEY hkey;


LONG error_code = RegOpenKeyEx(HKEY_CLASSES_ROOT,

" *",

0,

KEY_QUERY_VALUE | KEY_SET_VALUE,

& hkey);


if(error_code == ERROR_SUCCESS)

{

hkey.to_be_auto_destructed = true;

}

}

欢迎提出意见,问题和建议。


-JKop

解决方案

* JKop:


现在如果抛出异常,那么密钥确实关闭了。

无论如何,我的下一个想法是制作一个模板。这是否已经完成了?




Petri Marginean的ScopeGuard级。


查看文章关于ScopeGuard(Andrei Alexandrescu& Petri Marginean)

< url:http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/> ;,源代码

at< url:ftp://ftp.cuj.com/pub/2000/cujdec2000.zip>。


请注意,对于MSVC,你必须替换使用标准__LINE__和

Microsoft __COUNTER__使其一般工作,至少如果你使用的是

" edit&继续]该编译器的选项(它有点破碎)。


-

答:因为它弄乱了人们通常阅读文本的顺序。

问:为什么这么糟糕?

A:热门发布。

问:usenet上最烦人的事情是什么并在电子邮件中?


> ...

欢迎提出意见,问题和建议。




我更喜欢写这样的课程:

class CRegKey {

public:

HKEY hkey;

CRegKey(){

if (RegOpenKeyEx(& hkey))

抛出......

}

~CRegKey(){

RegCloseKey(hkey);

}

};


int main()

{

{

CRegKey regKey;

...

}

};


这个类的代码非常小,不值得制作模板

。这个类的一个不变量就是把手是打开的,所以你不需要b $ b必须测试它是否打开,你不必记得打开它和你

不必记得关闭它。只要它在范围内它就是开放的。


Niels Dybdahl


JKop写道:

使用MSWindows作为示例:

在MSWindows上,有一个叫做System Registry的东西,它是一个真正的大数据库,它拥有操作系统的所有设置。
使用注册表有API。我将关注的两个是:

RegOpenKeyEx
RegCloseKey

现在,这里有一些代码:

int main ()
{HKEY hkey;

RegOpenKeyEx(& hkey);

... //一些东西

RegCloseKey(hkey);
}

这里唯一的问题是如果在某些东西期间抛出异常,那么密钥永远不会被关闭。这是我的第一个解决方案:

上课HKEYe
{
公开:

HKEY hkey;
bool to_be_closed;

HKEYe():to_be_closed(false){}

〜HKEYe()
{
如果(to_be_closed)
{
RegCloseKey(hkey) );
}


运算符HKEY&(){return hkey; }
运算符const HKEY&()const {return hkey; }

HKEY * operator&(){return& hkey; const HKEY *运算符&()const {return& hkey; }
};

int main()
{
HKEYe hkey;

RegOpenKeyEx(& hkey);

hkey.to_be_closed = true;

// ...一些东西

RegCloseKey(hkey);
hkey.to_be_closed = false;

}

现在如果抛出异常,那么密钥就会关闭。

无论如何,我的下一个想法是制作一个模板。 。这之前已经完成了吗?无论如何,这是我的第一次尝试:

模板< class T>
类AutoDestructive
{
公开:

T t ;
bool to_be_auto_destructed;

AutoDestructive():t(),to_be_auto_destructed(false){}
template< class A> AutoDestructive(A a):t(a),to_be_auto_destructed
(false){}
template< class A> AutoDestructive(const A a):t(a),
to_be_auto_destructed(false){}
template< class A,class B> AutoDestructive(A a,B b):t(a,b),
to_be_auto_destructed(false){}
模板< A类,B类,C类> AutoDestructive(A a,B b,C c):t
(a,b,c),to_be_auto_destructed(false){}

virtual~AutoDestructive()= 0;

运营商T&(){return t;运算符const T&()const {return t; }

T * operator&(){return& t; }
const T * operator&()const {return& t; }类AutoDestructive_HKEY:public AutoDestructive< HKEY>
公开:

~AutoDestructive_HKEY()
{
如果(to_be_auto_destructed)RegCloseKey(t);
}
};

int main()
{/> AutoDestructive_HKEY hkey;

LONG error_code = RegOpenKeyEx(HKEY_CLASSES_ROOT,
" *",
0,
KEY_QUERY_VALUE | KEY_SET_VALUE,
& hkey);

if(error_code == ERROR_SUCCESS)
{
hkey.to_be_auto_destructed = true;
}
}

评论,问题和建议欢迎。




恭喜你,你刚才发明了 RAII成语。标准库中的std :: auto_ptr

类是RAII习语的示例。这个成语是在The C ++ Programming Language一书中描述的
。来自Bjarne

Stroustrup。使用析构函数进行适当的清理是一种众所周知的编写异常安全代码的方法。


这个习惯用法可以用于更多的情况而不是只是释放内存或

句柄。例如,在GUI应用程序中,您可以编写一个类,构造函数中的
将光标形状更改为沙漏,并在

析构函数中将光标恢复为其先前的形状。


void HeavyProcessing()

{

WaitCursor wc;


//在这里做一些事情....

//

//函数中的任何地方的异常或返回都将恢复光标形状。

}


-

Peter van Merkerk

peter.van.merkerk(at)dse.nl



Using MSWindows as an example:

On MSWindows, there''s a thing called the System Registry, which is a really
big database that holds all the settings of the OS. There''s API''s for
working with the registry. The two I will be concerned with are:

RegOpenKeyEx
RegCloseKey

Now, here''s some code:

int main()
{
HKEY hkey;

RegOpenKeyEx( &hkey );

... //some stuff

RegCloseKey( hkey );
}
The only problem here is that if an exception is thrown during "some stuff",
then the key never gets closed. Here was my first solution:

class HKEYe
{
public:

HKEY hkey;
bool to_be_closed;

HKEYe() : to_be_closed(false) {}

~HKEYe()
{
if (to_be_closed)
{
RegCloseKey(hkey);
}
}

operator HKEY&() { return hkey; }
operator const HKEY&() const { return hkey; }
HKEY* operator&() { return &hkey; }
const HKEY* operator&() const { return &hkey; }
};

int main()
{
HKEYe hkey;

RegOpenKeyEx( &hkey );

hkey.to_be_closed = true;

//... some stuff

RegCloseKey(hkey);
hkey.to_be_closed = false;

}
Now if an exception is thrown, then the key does get closed.

Anyway, my next thought was to make a template out of this. Has this been
done before? Anyway, here''s my first attempt:
template<class T>
class AutoDestructive
{
public:

T t;
bool to_be_auto_destructed;

AutoDestructive() : t(), to_be_auto_destructed(false) {}
template<class A> AutoDestructive(A a) : t(a), to_be_auto_destructed
(false) {}
template<class A> AutoDestructive(const A a) : t(a),
to_be_auto_destructed(false) {}
template<class A, class B> AutoDestructive(A a, B b) : t(a,b),
to_be_auto_destructed(false) {}
template<class A, class B, class C> AutoDestructive(A a, B b, C c) : t
(a,b,c), to_be_auto_destructed(false) {}

virtual ~AutoDestructive() = 0;

operator T&() { return t; }
operator const T&() const { return t; }
T* operator&() { return &t; }
const T* operator&() const { return &t; }
};

class AutoDestructive_HKEY : public AutoDestructive<HKEY>
{
public:

~AutoDestructive_HKEY()
{
if (to_be_auto_destructed) RegCloseKey(t);
}
};

int main()
{
AutoDestructive_HKEY hkey;

LONG error_code = RegOpenKeyEx(HKEY_CLASSES_ROOT,
"*",
0,
KEY_QUERY_VALUE|KEY_SET_VALUE,
&hkey);

if (error_code == ERROR_SUCCESS)
{
hkey.to_be_auto_destructed = true;
}
}
Comments, questions, suggestions welcomed.

-JKop

解决方案

* JKop:


Now if an exception is thrown, then the key does get closed.

Anyway, my next thought was to make a template out of this. Has this been
done before?



Petri Marginean''s ScopeGuard-class.

See the article about ScopeGuard (Andrei Alexandrescu & Petri Marginean) at
<url: http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/>, source code
at <url: ftp://ftp.cuj.com/pub/2000/cujdec2000.zip>.

Note that for MSVC you''ll have to replace use of standard __LINE__ with
Microsoft __COUNTER__ to make it work in general, at least if you''re using the
"edit & continue" option of that compiler (it''s a bit broken).

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?


> ...

Comments, questions, suggestions welcomed.



I prefer writing such a class like this:

class CRegKey {
public:
HKEY hkey;
CRegKey() {
if (RegOpenKeyEx( &hkey ))
throw...
}
~CRegKey() {
RegCloseKey( hkey );
}
};

int main()
{
{
CRegKey regKey;
...
}
};

The code for the class is so small that it is not worth making a template
for it. An invariant for the class is that the handle is open, so you do not
have to test if it is open, you do not have to remember to open it and you
do not have to remember to close it. As long as it is in scope it is open.

Niels Dybdahl


JKop wrote:

Using MSWindows as an example:

On MSWindows, there''s a thing called the System Registry, which is a really
big database that holds all the settings of the OS. There''s API''s for
working with the registry. The two I will be concerned with are:

RegOpenKeyEx
RegCloseKey

Now, here''s some code:

int main()
{
HKEY hkey;

RegOpenKeyEx( &hkey );

... //some stuff

RegCloseKey( hkey );
}
The only problem here is that if an exception is thrown during "some stuff",
then the key never gets closed. Here was my first solution:

class HKEYe
{
public:

HKEY hkey;
bool to_be_closed;

HKEYe() : to_be_closed(false) {}

~HKEYe()
{
if (to_be_closed)
{
RegCloseKey(hkey);
}
}

operator HKEY&() { return hkey; }
operator const HKEY&() const { return hkey; }
HKEY* operator&() { return &hkey; }
const HKEY* operator&() const { return &hkey; }
};

int main()
{
HKEYe hkey;

RegOpenKeyEx( &hkey );

hkey.to_be_closed = true;

//... some stuff

RegCloseKey(hkey);
hkey.to_be_closed = false;

}
Now if an exception is thrown, then the key does get closed.

Anyway, my next thought was to make a template out of this. Has this been
done before? Anyway, here''s my first attempt:
template<class T>
class AutoDestructive
{
public:

T t;
bool to_be_auto_destructed;

AutoDestructive() : t(), to_be_auto_destructed(false) {}
template<class A> AutoDestructive(A a) : t(a), to_be_auto_destructed
(false) {}
template<class A> AutoDestructive(const A a) : t(a),
to_be_auto_destructed(false) {}
template<class A, class B> AutoDestructive(A a, B b) : t(a,b),
to_be_auto_destructed(false) {}
template<class A, class B, class C> AutoDestructive(A a, B b, C c) : t
(a,b,c), to_be_auto_destructed(false) {}

virtual ~AutoDestructive() = 0;

operator T&() { return t; }
operator const T&() const { return t; }
T* operator&() { return &t; }
const T* operator&() const { return &t; }
};

class AutoDestructive_HKEY : public AutoDestructive<HKEY>
{
public:

~AutoDestructive_HKEY()
{
if (to_be_auto_destructed) RegCloseKey(t);
}
};

int main()
{
AutoDestructive_HKEY hkey;

LONG error_code = RegOpenKeyEx(HKEY_CLASSES_ROOT,
"*",
0,
KEY_QUERY_VALUE|KEY_SET_VALUE,
&hkey);

if (error_code == ERROR_SUCCESS)
{
hkey.to_be_auto_destructed = true;
}
}
Comments, questions, suggestions welcomed.



Congratulations, you just "invented" the RAII idiom. The std::auto_ptr
class in standard library is example of the RAII idiom. This idiom is
described in the book "The C++ Programming Language" from Bjarne
Stroustrup. Using the destructor to do proper clean up is a well known
C++ way to write exception safe code.

This idiom can be used for many more cases than just releasing memory or
handles. For example in a GUI application you could write a class that
in the constructor changes the cursor shape to an hourglass and in the
destructor restores the cursor to its previous shape.

void HeavyProcessing()
{
WaitCursor wc;

// Do some stuff here....
// Exceptions or returns anywhere in the
// function will restore the cursor shape.
}

--
Peter van Merkerk
peter.van.merkerk(at)dse.nl


这篇关于自动毁坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆