473,410 Members | 1,916 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,410 software developers and data experts.

Is this class exception safe

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_;
}

}

Nov 11 '07 #1
18 1739
digz wrote:
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;
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;
}
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;
}
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;
}
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
Nov 11 '07 #2
On Nov 11, 4:00 am, Kai-Uwe Bux <jkherci...@gmx.netwrote:
digz wrote:
[...]
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.
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

Nov 11 '07 #3
On Nov 11, 5:42 am, digz <Digvijo...@gmail.comwrote:
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;
}
}
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.

Nov 11 '07 #4
On Nov 11, 7:36 pm, James Kanze <james.ka...@gmail.comwrote:
On Nov 11, 4:00 am, Kai-Uwe Bux <jkherci...@gmx.netwrote:
digz wrote:

[...]
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.

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.
Ok I read up the Copy and Swap Idiom , and now my assigment operator
looks like this :
Is this correct ?

cacheSType& cacheSType::operator=(const cacheSType& rhs) {
if ( &rhs != this )
{
cacheSType tmp(rhs);
std::swap(tmp._cache_t, cache_t);
data_t = rhs.data_t;
}
return *this;
}
Nov 11 '07 #5
On Nov 11, 9:54 pm, terminator <farid.mehr...@gmail.comwrote:
On Nov 11, 5:42 am, digz <Digvijo...@gmail.comwrote:


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;
}
}

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).*/
Dont understand why you did this ? What purpose does the anonymous
union serve ?
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

}
Thx
Digz

Nov 11 '07 #6
On Nov 11, 10:31 pm, digz <Digvijo...@gmail.comwrote:
On Nov 11, 7:36 pm, James Kanze <james.ka...@gmail.comwrote:


On Nov 11, 4:00 am, Kai-Uwe Bux <jkherci...@gmx.netwrote:
digz wrote:
[...]
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.
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.

Ok I read up the Copy and Swap Idiom , and now my assigment operator
looks like this :
Is this correct ?

cacheSType& cacheSType::operator=(const cacheSType& rhs) {
if ( &rhs != this )
{
cacheSType tmp(rhs);
std::swap(tmp._cache_t, _cache_t);
std::swap(tmp._data_t, _data_t);
}
return *this;

}- Hide quoted text -
Added the extra line std::swap(tmp._data_t, _data_t ) in the
assignment operator
Had to swap the _data_t otherwise tmp was in an inconsistent state ,
and the tmp destructor call was segfaulting
If there is still something wrong please let me know
Thanks very much for all your comments.
--Digz

Nov 11 '07 #7
digz wrote:
On Nov 11, 10:31 pm, digz <Digvijo...@gmail.comwrote:
>On Nov 11, 7:36 pm, James Kanze <james.ka...@gmail.comwrote:


On Nov 11, 4:00 am, Kai-Uwe Bux <jkherci...@gmx.netwrote:
digz wrote:
[...]
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.
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.

Ok I read up the Copy and Swap Idiom , and now my assigment operator
looks like this :
Is this correct ?

cacheSType& cacheSType::operator=(const cacheSType& rhs) {
if ( &rhs != this )
{
cacheSType tmp(rhs);
std::swap(tmp._cache_t, _cache_t);
std::swap(tmp._data_t, _data_t);
> }
return *this;
This looks right.

BTW: the test for self-assignment is not needed for correctness. Whether it
increases or decreases performance depends on how frequent self-assignment
is in the application.
Also: you could move the two swap lines to a swap friend function

friend
void swap ( cacheSType & rhs, cacheSType lhs ) {
std::swap( lhs._cache_t, rhs._cache_t );
std::swap( lhs._data_t, rhs._data_t );
}

and then call that in the assignment operator. This swap() could then be
used in other places instead of std::swap<cacheSType>, which would call
your assignment-operator three times resulting in 6 member-swaps as opposed
to only two.

>}- Hide quoted text -
Added the extra line std::swap(tmp._data_t, _data_t ) in the
assignment operator
Had to swap the _data_t otherwise tmp was in an inconsistent state ,
and the tmp destructor call was segfaulting
If there is still something wrong please let me know

Best

Kai-Uwe Bux
Nov 11 '07 #8
Kai-Uwe Bux wrote:

[...]
BTW: the test for self-assignment is not needed for correctness.
In general (there are probably exceptions), the need for a test
for self-assignment is often a sign that the assignment operator
is not excetpion safe (but as you point out, it's not necessary
here).
Whether it increases or decreases performance depends on how
frequent self-assignment is in the application.
Also: you could move the two swap lines to a swap friend function
friend
void swap ( cacheSType & rhs, cacheSType lhs ) {
std::swap( lhs._cache_t, rhs._cache_t );
std::swap( lhs._data_t, rhs._data_t );
}
and then call that in the assignment operator. This swap()
could then be used in other places instead of
std::swap<cacheSType>, which would call your
assignment-operator three times resulting in 6 member-swaps as
opposed to only two.
I think it would be more idiomatic to have a swap member
fucntion, and specialize std::swap to use it. I usually assume
that if a class does not have a swap member function, std::swap
will be done using the "standard" algorithm, with copy
construction and assignment, and don't use the swap idiom if my
class contains members of class type which don't have a swap
member function.

--
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

Nov 12 '07 #9
James Kanze wrote:
Kai-Uwe Bux wrote:

[...]
>BTW: the test for self-assignment is not needed for correctness.

In general (there are probably exceptions), the need for a test
for self-assignment is often a sign that the assignment operator
is not excetpion safe (but as you point out, it's not necessary
here).
>Whether it increases or decreases performance depends on how
frequent self-assignment is in the application.
>Also: you could move the two swap lines to a swap friend function
> friend
void swap ( cacheSType & rhs, cacheSType lhs ) {
std::swap( lhs._cache_t, rhs._cache_t );
std::swap( lhs._data_t, rhs._data_t );
}
>and then call that in the assignment operator. This swap()
could then be used in other places instead of
std::swap<cacheSType>, which would call your
assignment-operator three times resulting in 6 member-swaps as
opposed to only two.

I think it would be more idiomatic to have a swap member
fucntion, and specialize std::swap to use it.
I disagree (or at least I would contend that what is idiomatic in this area
is shifting). I just put a swap() function into the same namespace as the
class. Then name-lookup will find it. Note that the next version of the
standard makes this (and not a swap member function) one of the two ways to
satisfy the swappable requirement.

I usually assume
that if a class does not have a swap member function, std::swap
will be done using the "standard" algorithm, with copy
construction and assignment,
That assumption could also be correct for classes that have a swap member.
You are heavily relying on (local) coding conventions should you assume
that std::swap is specialized for classes that have a swap member.

I follow the convention not to use std::swap, but swap (usually after making
std::swap visible via "using"). This way, I can swap everything swappable.
I think next version of the standard will ensure that standard algorithm
will use swap and not std::swap so that I specializing std::swap is
superfluous.

and don't use the swap idiom if my
class contains members of class type which don't have a swap
member function.
I just assume that members are swappable. _If_ the swap is no-throw for
_all_ members, then so is mine (and copy-swap-assignment will be exception
safe).
Best

Kai-Uwe Bux
Nov 12 '07 #10
Alf P. Steinbach wrote:
* Kai-Uwe Bux:
>>
I follow the convention not to use std::swap, but swap (usually after
making std::swap visible via "using"). This way, I can swap everything
swappable. I think next version of the standard will ensure that standard
algorithm will use swap and not std::swap so that I specializing
std::swap is superfluous.

Well, currently it's formally invalid to specialize any function in
namespace std: classes yes, functions no, njet, nein, nei, nope. Very
stupid rule. I just ignore it for my own private small programs. ;-)
I thought so, too; and I was about to mention it. However, then I looked up
the wording:

A program may add template specializations for any standard library
template to namespace std.

Now, I used to think that one cannot provide alternative specializations for
function templates (all one can do is to add overloads). Then, I used the
pdf-reader to search for specializations and found that the standard
acknowledges the existence of function template specializations (oops). At
that point, I was not sure anymore whether my previous thinking was correct
(it's kind of late). That's why I dropped the issue.
Best

Kai-Uwe Bux
Nov 12 '07 #11
"Alf P. Steinbach" <al***@start.nowrote in
news:13*************@corp.supernews.com:
* Kai-Uwe Bux:
>>
I follow the convention not to use std::swap, but swap (usually after
making std::swap visible via "using"). This way, I can swap
everything swappable. I think next version of the standard will
ensure that standard algorithm will use swap and not std::swap so
that I specializing std::swap is superfluous.

Well, currently it's formally invalid to specialize any function in
namespace std: classes yes, functions no, njet, nein, nei, nope. Very
stupid rule. I just ignore it for my own private small programs. ;-)
Chapter and verse?

I found 17.4.3.1.1 which specifically mentions: "A program may add template
specializations for any standard library template to namespace std." This
seems to specifically allow one to specialize std::swap for one's own
classes.
Nov 12 '07 #12
On Nov 12, 2:52 pm, "Alf P. Steinbach" <al...@start.nowrote:
* Andre Kostur:
"Alf P. Steinbach" <al...@start.nowrote in
news:13*************@corp.supernews.com:
* Kai-Uwe Bux:
I follow the convention not to use std::swap, but swap (usually after
making std::swap visible via "using"). This way, I can swap
everything swappable. I think next version of the standard will
ensure that standard algorithm will use swap and not std::swap so
that I specializing std::swap is superfluous.
Well, currently it's formally invalid to specialize any function in
namespace std: classes yes, functions no, njet, nein, nei, nope. Very
stupid rule. I just ignore it for my own private small programs. ;-)
Chapter and verse?
I found 17.4.3.1.1 which specifically mentions: "A program
may add template specializations for any standard library
template to namespace std." This seems to specifically
allow one to specialize std::swap for one's own classes.
That only covers template specializations.
Here's a template specialization of std::swap:
namespace std
{
template<void swap( MyClass& a, MyClass& b ) { a.swap( b ) }
}
and that is OK,
And that's what we're talking about.

--
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

Nov 13 '07 #13
Kai-Uwe Bux wrote:
James Kanze wrote:
[...]
The question is not how a member swap is implemented. The
question is whether a swap member function indicates that
std::swap<is properly specialized. (Also, with regard to the
issues discusses elsethread, I would wonder how many times
std::swap<is improperly overloaded:-)
As I said, in my own classes, I use the member function for
class types; I don't suppose std::swap is properly specialized.
I see. For the template stuff that I am dealing with, this
would be the most inconvenient convention.
This is probably the difference. The only times I use templates
are in very low level stuff. In which case, the only class
types I have to deal with are my own, or those in the standard
library; there are no other libraries below me. And of course,
the class types in my own code and in the standard library all
have a member swap. Using it (and explicitly std::swap for the
non class types) avoids the name lookup issue of calling swap
from within a function named swap.
I can see, however, that it is probably the most
convenient for you (and it makes the least assumptions).
In the concrete situations I've had to deal with to date:-).

--
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
Nov 15 '07 #14
On Nov 10, 6:42 pm, digz <Digvijo...@gmail.comwrote:
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
-------------------

what is wrong with boost::any
?
See also:

http://www.boost.org/doc/html/any.html
Nov 15 '07 #15
On Nov 16, 7:27 am, ExcessPh...@gmail.com wrote:
On Nov 10, 6:42 pm, digz <Digvijo...@gmail.comwrote:
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
-------------------

what is wrong with boost::any
?
See also:

http://www.boost.org/doc/html/any.html
I wanted something lightweight, I am always going to store ints,
doubles or strings, (if i ever need to store bigger objects i will
probably serialize them as strings and deserialize while retrieving ),
have to write lot of code around boost::any to identify types at
runtime and dispatch to the right method...

boost::variant another option( types fixed at compile time) also leads
to huge binaries, i have to write the visitation code.., compiling
requires -ftemplate-depth 50 .something which co workers do not like
coz increased template depth .mean crazy build times..for the source
tree...
to cut a long story short keep it nice and simple.!
Nov 16 '07 #16
On Nov 11, 3:54 pm, terminator <farid.mehr...@gmail.comwrote:
On Nov 11, 5:42 am, digz <Digvijo...@gmail.comwrote:


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;
}
}

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){}
//oops I mean:
cacheSType(int i): _data_t(INTEGER), i_(i){}
cacheSType(double d): _data_t(DOUBLE), _cache_t(d){}
//and:
cacheSType(double d): _data_t(DOUBLE), d_(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.- Hide quoted text -

- Show quoted text -
regards,
FM.
Nov 18 '07 #17
On Nov 15, 3:05 pm, James Kanze <james.ka...@gmail.comwrote:
Kai-Uwe Bux wrote:
James Kanze wrote:

[...]
>The question is not how a member swap is implemented. The
>question is whether a swap member function indicates that
>std::swap<is properly specialized. (Also, with regard to the
>issues discusses elsethread, I would wonder how many times
>std::swap<is improperly overloaded:-)
As I said, in my own classes, I use the member function for
class types; I don't suppose std::swap is properly specialized.
I see. For the template stuff that I am dealing with, this
would be the most inconvenient convention.

This is probably the difference. The only times I use templates
are in very low level stuff. In which case, the only class
types I have to deal with are my own, or those in the standard
library; there are no other libraries below me. And of course,
the class types in my own code and in the standard library all
have a member swap. Using it (and explicitly std::swap for the
non class types) avoids the name lookup issue of calling swap
from within a function named swap.
I can see, however, that it is probably the most
convenient for you (and it makes the least assumptions).

In the concrete situations I've had to deal with to date:-).

--
James Kanze (GABI Software) email:james.ka...@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
forgive me for not reading the whole argument about ways to define
swap,but I ask why not to force standard to be like this:

namespace std{
template <swapable T>
void swap(T& l,T&r){
if(&l!==&r)l.swap(r);
};

template<unswapable T>
void swap(T& l,T&r){
TripleAssign(l,r)
};

template<intrinsic T>
void swap(T& l,T&r);

template<assignable T>
where copyable<T>
TripleAssign(T& l,T&r){
T t(l);
l=r;
r=t;
};

template<swapable T>
swap_assign(T& dest,const T& src){
T t(src);
swap(dest,t);
};
};

in the absence of cocepts three overloads can be three distinct
templates with distinct names(just as TripleAsssign).This also lets
the programer to properly decide about the swapabitily of his class.

programmer code:

const class A& A::operator=(const A& r){
swap_assign(*this,r);
};
regards,
FM.
Nov 18 '07 #18
James Kanze wrote:
For that matter, you can have all three: a member swap (which
seems the most natural to me), a free-standing swap in the
ambient namespace which calls it, and a specialization of
std::swap.
It's really a shame that K&R C didn't have a swap operator. It might have
had one; I think that many machines had swap opcodes, and compilers didn't
optimize very well. It would have made a lot of sense to define x <-y to
do the same thing as the three-assignment idiom, but more efficiently. Then
this whole silly problem would never have existed. You could define
operator<-as a member or a non-member as you liked, or omit it entirely
since the default definition would be correct for most classes (far more
than the default operator= is correct for). There would be no need for the
three-assignment std::swap, so no worries about someone calling it by
accident. It's funny how much in life hinges on syntax.

-- Ben
Nov 28 '07 #19

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: Suzanne Vogel | last post by:
Hi, Given: I have a class with protected or private data members, some of them without accessor methods. It's someone else's class, so I can't change it. (eg, I can't add accessor methods to the...
17
by: pub | last post by:
When creating a list: list<class A*> l; How to delete all the objects whose pointers are contained in "l"? Thanks for your comments?
23
by: YinTat | last post by:
Hi, I learned C++ recently and I made a string class. A code example is this: class CString { public: inline CString(const char *rhs) { m_size = strlen(rhs);
3
by: Scott Brady Drummonds | last post by:
Hello, all, My most recent assignment has me working on a medium- to large-sized Windows-based C++ software project. My background is entirely on UNIX systems, where it appears that most of my...
822
by: Turamnvia Suouriviaskimatta | last post by:
I 'm following various posting in "comp.lang.ada, comp.lang.c++ , comp.realtime, comp.software-eng" groups regarding selection of a programming language of C, C++ or Ada for safety critical...
21
by: Michael Bierman | last post by:
Please forgive the simplicy of this question. I have the following code which attempts to determine the color of some text and set other text to match that color. It works fine in Firefox, but does...
11
by: Richard Lewis Haggard | last post by:
Is it possible to put a reference to an object inside of a class? If so, what is the syntax? The reason I want to do this is so that I can make a copy of the original object, make modifications to...
7
by: dragoncoder | last post by:
Hello experts, I have the following code me. =cat mystring.h #include<iostream> using namespace std; class mystring {
7
by: Charles Zhang | last post by:
I want to know to the following in a safe manner (the following code will be dangerous if p does not contain a pointer to MyClass). I would like someone to show me a better way (either throw an...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.