此类异常是否安全 [英] Is this class exception safe

查看:86
本文介绍了此类异常是否安全的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我正在尝试编写一个封装了一个Union的类,我想这个代码是异常安全的。

有人可以查看它并告诉我,如果我做了正确的

的事情,有没有明显的内存泄漏或糟糕的设计,无能

来弥补最有可能的失败路径等..?。


提前致谢

Digz

------------ -------


#include< exception>

enum datatype {INVALID = -1,INTEGER = 1,STRING,DOUBLE};


struct cacheSType

{

private:

union cacheUType

{

int i_;

double d_;

char * cptr_;

cacheUType():d _( - 999){}

cacheUType(int i):i_(i){}

cacheUType(double d):d_(d){}

cacheUType(char * c):cptr_(c){}

};

typedef cacheUType unionType;

datatype _data_t;

unionType _cache_t;

public:

cacheSType():_ data_t(INVALID){}

cacheSType(int i):_ data_t(INTEGER),_ cache_t(i){}

cacheSType(double d):_ data_t(DOUBLE),_ cache_t(d){}

cacheSType(const char * c):_ data_t(STRING){

try {

_cache_t.cptr_ = new char [strlen(c)+ 1];

strcpy(_cache_t.cptr_,c);

}

catch(const std :: bad_alloc& oom){

cerr<< oom.what()<< endl;

throw;

}

catch(...){

throw;

}

}


cacheSType(const cacheSType& rhs){

try {

if(rhs._data_t == STRING){

_cache_t.cptr_ = new

char [strlen(rhs._cache_t.cptr_)+ 1];

strcpy(_cache_t.cptr_,rhs._cache_t.cptr_);

}

else {

_cache_t = rhs._cache_t ;

}

_data_t = rhs._data_t;

}

catch(const std :: bad_alloc& oom){

cerr<< oom.what()<< endl;

throw;

}

catch(...){

throw;

}

}


cacheSType& operator =(const cacheSType& rhs){

if(& rhs!= this){

if(rhs._data_t!= STRING){

if(_data_t == STRING)

delete [] _cache_t.cptr_;

_cache_t = rhs._cache_t;

}

else {

if(_data_t == STRING)

delete [] _cache_t.cptr_;

try {

_cache_t.cptr_ = new

char [strlen(rhs._cache_t.cptr_)+ 1];

}

catch(const std :: bad_alloc& oom){

cout<< oom.what()<< endl;

throw;

}

catch(...){

throw;

}

strcpy(_cache_t.cptr_,rhs._cache_t.cptr_);

}

_data_t = rhs._data_t;

}

返回* this;

}


operator int(){

if(_data_t == INTEGER)

return _cache_t.i_;

throw std :: bad_cast(); //不能返回任何明智的东西

如果不是int

}


operator double(){

如果(_data_t == DOUBLE)

返回_cache_t.d_;

抛出std :: bad_cast();

}


运算符const char *(){

if(_data_t == STRING)

return _cache_t.cptr_;

throw std :: bad_cast();

}


~cacheSType(){

if(_data_t == STRING)

删除[] _cache_t.cptr_;

}


}

Hi ,
I am trying to write a class that encapsulates a Union within it , I
intend the code to be exception safe.
can someone please review it and tell me if I have done the right
thing , are there any obvious memory leaks or bad design , inability
to cover most likely failure paths etc..?.

Thanks in advance
Digz
-------------------

#include<exception>
enum datatype { INVALID=-1, INTEGER=1, STRING, DOUBLE };

struct cacheSType
{
private:
union cacheUType
{
int i_;
double d_;
char* cptr_;
cacheUType():d_(-999){}
cacheUType(int i):i_(i){}
cacheUType(double d):d_(d){}
cacheUType(char* c):cptr_(c){}
};
typedef cacheUType unionType;
datatype _data_t;
unionType _cache_t;

public:
cacheSType():_data_t(INVALID){}
cacheSType(int i): _data_t(INTEGER), _cache_t(i){}
cacheSType(double d): _data_t(DOUBLE), _cache_t(d){}
cacheSType(const char* c ): _data_t(STRING){
try {
_cache_t.cptr_ = new char[strlen(c) + 1 ];
strcpy(_cache_t.cptr_, c);
}
catch( const std::bad_alloc &oom ){
cerr << oom.what() << endl;
throw;
}
catch(...) {
throw;
}
}

cacheSType( const cacheSType& rhs) {
try {
if ( rhs._data_t == STRING ) {
_cache_t.cptr_ = new
char[strlen(rhs._cache_t.cptr_) + 1];
strcpy(_cache_t.cptr_, rhs._cache_t.cptr_);
}
else {
_cache_t = rhs._cache_t;
}
_data_t = rhs._data_t;
}
catch( const std::bad_alloc &oom) {
cerr << oom.what() << endl;
throw;
}
catch(...) {
throw;
}
}

cacheSType& operator=(const cacheSType& rhs) {
if ( &rhs != this ) {
if ( rhs._data_t != STRING ) {
if ( _data_t == STRING)
delete [] _cache_t.cptr_;
_cache_t = rhs._cache_t;
}
else{
if ( _data_t == STRING )
delete [] _cache_t.cptr_;
try {
_cache_t.cptr_= new
char[strlen(rhs._cache_t.cptr_) + 1];
}
catch( const std::bad_alloc &oom) {
cout << oom.what() << endl;
throw;
}
catch(...) {
throw;
}
strcpy( _cache_t.cptr_, rhs._cache_t.cptr_);
}
_data_t = rhs._data_t;
}
return *this;
}

operator int () {
if ( _data_t == INTEGER )
return _cache_t.i_;
throw std::bad_cast(); //cannot return anything sensible
if not int
}

operator double () {
if ( _data_t == DOUBLE )
return _cache_t.d_;
throw std::bad_cast();
}

operator const char* () {
if ( _data_t == STRING )
return _cache_t.cptr_;
throw std::bad_cast();
}

~cacheSType(){
if ( _data_t == STRING )
delete [] _cache_t.cptr_;
}

}

推荐答案

digz写道:
digz wrote:



我正在尝试写一个封装的类在其中的联盟,我

打算将代码设置为异常安全。

有人可以查看它并告诉我我是否做得对吗

的东西,有没有明显的内存泄漏或糟糕的设计,无法

来覆盖最可能的故障路径等。?。

提前致谢

Digz

-------------------


#include< exception>

enum datatype {INVALID = -1,INTEGER = 1,STRING,DOUBLE};


struct cacheSType

{

private:

union cacheUType

{

int i_ ;

double d_;

char * cptr_;

cacheUType():d _( - 999){}

cacheUType(int i):i_(i){}

cacheUType(double d):d_(d){}

cacheUType(char * c):cptr_( c){}

};

typedef cacheUType unionType;
Hi ,
I am trying to write a class that encapsulates a Union within it , I
intend the code to be exception safe.
can someone please review it and tell me if I have done the right
thing , are there any obvious memory leaks or bad design , inability
to cover most likely failure paths etc..?.

Thanks in advance
Digz
-------------------

#include<exception>
enum datatype { INVALID=-1, INTEGER=1, STRING, DOUBLE };

struct cacheSType
{
private:
union cacheUType
{
int i_;
double d_;
char* cptr_;
cacheUType():d_(-999){}
cacheUType(int i):i_(i){}
cacheUType(double d):d_(d){}
cacheUType(char* c):cptr_(c){}
};
typedef cacheUType unionType;



是否有理由使用typedef而不只是说


union unionType {...

Is there a reason to use a typedef instead of just saying

union unionType {...


datatype _data_t;

unionType _cache_t;


public:

cacheSType( ):_ data_t(INVALID){}

cacheSType(int i):_ data_t(INTEGER),_ cache_t(i){}

cacheSType(double d):_ data_t(DOUBLE) ),_ cache_t(d){}

cacheSType(const char * c):_ data_t(STRING){

try {

_cache_t.cptr_ = new char [strlen(c)+ 1];

strcpy(_cache_t.cptr _,c);

}

catch(const std :: bad_alloc& oom){

cerr<< oom.what()<< endl;

throw;

}

catch(...){

throw;

}
datatype _data_t;
unionType _cache_t;

public:
cacheSType():_data_t(INVALID){}
cacheSType(int i): _data_t(INTEGER), _cache_t(i){}
cacheSType(double d): _data_t(DOUBLE), _cache_t(d){}
cacheSType(const char* c ): _data_t(STRING){
try {
_cache_t.cptr_ = new char[strlen(c) + 1 ];
strcpy(_cache_t.cptr_, c);
}
catch( const std::bad_alloc &oom ){
cerr << oom.what() << endl;
throw;
}
catch(...) {
throw;
}



我不确定catch(...){throw;}是否做了什么。它似乎只是
重新抛出一个异常,否则它会在堆栈中传播

无论如何。

I am not sure whether catch(...){throw;} does anything. It seems to just
rethrow an exception that otherwise would have propagates up the stack
anyway.


}


cacheSType(const cacheSType& rhs){

try {

if(rhs._data_t == STRING){

_cache_t.cptr_ = new

char [strlen(rhs._cache_t.cptr_)+ 1];

strcpy(_cache_t.cptr_,rhs._cache_t .cptr _);

}

else {

_cache_t = rhs._cache_t;

}

_data_t = rhs._data_t;

}

catch(const std :: bad_alloc& oom){

cerr< < oom.what()<< endl;

throw;

}

catch(...){

throw;

}

}


cacheSType& operator =(const cacheSType& rhs){

if(& rhs!= this){

if(rhs._data_t!= STRING){

if(_data_t == STRING)

delete [] _cache_t.cptr_;

_cache_t = rhs._cache_t;

}

else {

if(_data_t == STRING)

delete [] _cache_t.cptr_;

try {

_cache_t.cptr_ = new

char [strlen(rhs._cache_t.cptr_)+ 1];

}

catch(const std :: bad_alloc& oom){

cout<< oom.what()<< endl;

throw;

}

catch(...){

throw;

}
}

cacheSType( const cacheSType& rhs) {
try {
if ( rhs._data_t == STRING ) {
_cache_t.cptr_ = new
char[strlen(rhs._cache_t.cptr_) + 1];
strcpy(_cache_t.cptr_, rhs._cache_t.cptr_);
}
else {
_cache_t = rhs._cache_t;
}
_data_t = rhs._data_t;
}
catch( const std::bad_alloc &oom) {
cerr << oom.what() << endl;
throw;
}
catch(...) {
throw;
}
}

cacheSType& operator=(const cacheSType& rhs) {
if ( &rhs != this ) {
if ( rhs._data_t != STRING ) {
if ( _data_t == STRING)
delete [] _cache_t.cptr_;
_cache_t = rhs._cache_t;
}
else{
if ( _data_t == STRING )
delete [] _cache_t.cptr_;
try {
_cache_t.cptr_= new
char[strlen(rhs._cache_t.cptr_) + 1];
}
catch( const std::bad_alloc &oom) {
cout << oom.what() << endl;
throw;
}
catch(...) {
throw;
}



如果上面抛出,你已经删除了当前的字符串。然后,对象

处于不一致状态,因为_cache_t表示它是一个字符串,但

字符串字段指向释放的内存。从这个意义上说,

赋值运算符不是异常安全的。

此外,赋值运算符的逻辑很难遵循(毕竟,

有9种可能的_data_t和rhs._data_t组合考虑)。

为了清晰和异常安全,你应该考虑使用复制交换

idiom。 br />

If the above throws, you have already deleted the current string. The object
is then in an inconsistent state since the _cache_t says it''s a string, but
the string-field points to deallocated memory. In that sense, the
assignment operator is not exception safe.
Also, the logic of the assignment operator is hard to follow (after all,
there are 9 possible combinations of _data_t and rhs._data_t to consider).
For clarity and exception safety, you should consider using the copy-swap
idiom.


strcpy(_cache_t.cptr_,rhs._cache_t.cptr_);

}

_data_t = rhs._data_t;

}

返回* this;

}


operator int( ){

if(_data_t == INTEGER)

return _cache_t.i_;

throw std :: bad_cast(); //不能返回任何明智的东西

如果不是int

}


operator double(){

如果(_data_t == DOUBLE)

返回_cache_t.d_;

抛出std :: bad_cast();

}


运算符const char *(){

if(_data_t == STRING)

return _cache_t.cptr_;

throw std :: bad_cast();

}


~cacheSType(){

if(_data_t == STRING)

删除[] _cache_t.cptr_;

}


}
strcpy( _cache_t.cptr_, rhs._cache_t.cptr_);
}
_data_t = rhs._data_t;
}
return *this;
}

operator int () {
if ( _data_t == INTEGER )
return _cache_t.i_;
throw std::bad_cast(); //cannot return anything sensible
if not int
}

operator double () {
if ( _data_t == DOUBLE )
return _cache_t.d_;
throw std::bad_cast();
}

operator const char* () {
if ( _data_t == STRING )
return _cache_t.cptr_;
throw std::bad_cast();
}

~cacheSType(){
if ( _data_t == STRING )
delete [] _cache_t.cptr_;
}

}



Best


Kai-Uwe Bux


Best

Kai-Uwe Bux


11月11日凌晨4:00,Kai-Uwe Bux< jkherci ... @ gmx.netwrote:
On Nov 11, 4:00 am, Kai-Uwe Bux <jkherci...@gmx.netwrote:

digz写道:
digz wrote:



[...]

[...]


此外,还有赋值运算符的逻辑很难遵循

(毕竟,_data_t和

rhs._data_t有9种可能的组合要考虑)。为了清晰和异常安全,您应该考虑使用复制交换习语。
Also, the logic of the assignment operator is hard to follow
(after all, there are 9 possible combinations of _data_t and
rhs._data_t to consider). For clarity and exception safety,
you should consider using the copy-swap idiom.



在这种情况下,绝对是。我可以补充一点,你可以在他的工会上调用

std :: swap,并且结果保证不会是

throw(因为工会将有一个简单的复制构造函数,

析构函数和赋值运算符,除非用户定义它们

本人)。换句话说,在进行交换时,他不必分析工会所包含的类型




-

James Kanze(GABI Software)电子邮件:ja ********* @ gmail.com

Conseils eninformatiqueorientéeobjet/

Beratung in objektorientierter Datenverarbeitung

9placeSémard,78210 St.-Cyr-l''coco,France,+ 33(0)1 30 23 00 34

In this case, definitely. I might add that you can call
std::swap on his union, and the results are guaranteed to be no
throw (since a union will have a trivial copy constructor,
destructor and assignment operator, unless the user defines them
himself). In other words, he doesn''t have to analyse the type
contained by the union when doing the swap.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l''école, France, +33 (0)1 30 23 00 34


11月11日上午5:42,digz< Digvijo ... @ gmail.comwrote:
On Nov 11, 5:42 am, digz <Digvijo...@gmail.comwrote:



我正在尝试编写一个封装了一个Union的类,我想b $ b打算将代码设置为异常安全。

有人可以查看它并告诉我是否我做了正确的

的事情,是否有任何明显的内存泄漏或糟糕的设计,无力

来覆盖最可能的故障路径等。?。


提前致谢

Digz

-------------------


#include< exception>

enum datatype {INVALID = -1,INTEGER = 1,STRING,DOUBLE};


struct cacheSType

{

private:

union cacheUType

{

int i_;

double d_;

char * cptr_;

cacheUType():d _( - 999){}

cacheUType(int i) :i_(i){}

cacheUType(double d):d_(d){}

cacheUType(char * c):cptr_(c){}

};

typedef cacheUType unionType;

datatype _data_t;

unionType _cache_t;


public:

cacheSType():_ data_t(INVALID){}

cacheSType(int i):_ data_t(INTEGER),_ cache_t(i){}

cacheSType(double d):_ data_t(DOUBLE),_ cache_t(d){}

cacheSType(const char * c):_ data_t(STRING){

尝试{

_cache_t.cptr_ = new char [strlen(c)+ 1];

strcpy(_cache_t.cptr_,c);

}

catch(const std :: bad_alloc& oom){

cerr<< oom.what()<< endl;

throw;

}

catch(...){

throw;

}

}


cacheSType(const cacheSType& rhs){

try {

if(rhs._data_t == STRING){

_cache_t.cptr_ = new

char [strlen(rhs._cache_t.cptr_)+ 1];

strcpy(_cache_t.cptr_,rhs._cache_t.cptr_);

}

else {

_cache_t = rhs._cache_t ;

}

_data_t = rhs._data_t;

}

catch(const std :: bad_alloc& oom){

cerr<< oom.what()<< endl;

throw;

}

catch(...){

throw;

}

}
Hi ,
I am trying to write a class that encapsulates a Union within it , I
intend the code to be exception safe.
can someone please review it and tell me if I have done the right
thing , are there any obvious memory leaks or bad design , inability
to cover most likely failure paths etc..?.

Thanks in advance
Digz
-------------------

#include<exception>
enum datatype { INVALID=-1, INTEGER=1, STRING, DOUBLE };

struct cacheSType
{
private:
union cacheUType
{
int i_;
double d_;
char* cptr_;
cacheUType():d_(-999){}
cacheUType(int i):i_(i){}
cacheUType(double d):d_(d){}
cacheUType(char* c):cptr_(c){}
};
typedef cacheUType unionType;
datatype _data_t;
unionType _cache_t;

public:
cacheSType():_data_t(INVALID){}
cacheSType(int i): _data_t(INTEGER), _cache_t(i){}
cacheSType(double d): _data_t(DOUBLE), _cache_t(d){}
cacheSType(const char* c ): _data_t(STRING){
try {
_cache_t.cptr_ = new char[strlen(c) + 1 ];
strcpy(_cache_t.cptr_, c);
}
catch( const std::bad_alloc &oom ){
cerr << oom.what() << endl;
throw;
}
catch(...) {
throw;
}
}

cacheSType( const cacheSType& rhs) {
try {
if ( rhs._data_t == STRING ) {
_cache_t.cptr_ = new
char[strlen(rhs._cache_t.cptr_) + 1];
strcpy(_cache_t.cptr_, rhs._cache_t.cptr_);
}
else {
_cache_t = rhs._cache_t;
}
_data_t = rhs._data_t;
}
catch( const std::bad_alloc &oom) {
cerr << oom.what() << endl;
throw;
}
catch(...) {
throw;
}
}



我会这样写:


struct cacheSType {

private:

union unionType {

int i_;

double d_;

char * cptr_;

};


union {//匿名联盟本身就是一个对象

unionType _cache_t; //仅供复制

int i_;

double d_;

char * cptr_;

}; / *所有成员都属于嵌套块(struct cacheSType)。* /


数据类型_data_t;


cacheSType():_ data_t(INVALID){ } $ / $
cacheSType(int i):_ data_t(INTEGER),_ cache_t(i){}

cacheSType(double d):_ data_t(DOUBLE),_ cache_t(d){ } $ / $
cacheSType(const char * c):_ data_t(STRING){getstr(c); };

cacheSType(const cacheSType& rhs):

_cache_t(rhs._cache_t),

_data_t(rhs._data_t){

if(_data_T == STRING)

getstr(rhs.cptr_);

};


cacheSType&安培; operator =(const cacheSType& rhs); //通过copy定义 -

swap。


~cacheSType(){

if(_data_t == STRING)

delete [] cptr_;

//只是为了确保不会使用无效数据:

_data_t = INVALID;

cptr_ = NULL;

};


void getstr(const char * c); //处理内存分配


}


问候,

FM。

I would write it this way:

struct cacheSType{
private:
union unionType{
int i_;
double d_;
char* cptr_;
};

union{//anonymous union is an object itself
unionType _cache_t;//for copying only
int i_;
double d_;
char* cptr_;
};/*all members belong to nesting block(struct cacheSType).*/

datatype _data_t;

cacheSType():_data_t(INVALID){}
cacheSType(int i): _data_t(INTEGER), _cache_t(i){}
cacheSType(double d): _data_t(DOUBLE), _cache_t(d){}
cacheSType(const char* c ): _data_t(STRING){ getstr(c); };
cacheSType( const cacheSType& rhs):
_cache_t(rhs._cache_t),
_data_t(rhs._data_t){
if(_data_T==STRING)
getstr(rhs.cptr_);
};

cacheSType& operator=(const cacheSType& rhs);//defined via copy-
swap.

~cacheSType(){
if ( _data_t == STRING )
delete [] cptr_;
//just to make sure invalid data wont be used:
_data_t=INVALID;
cptr_=NULL;
};

void getstr(const char* c);//handles memory allocation

}

regards,
FM.


这篇关于此类异常是否安全的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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