Is this class exception safe

Discussion in 'C++' started by digz, Nov 11, 2007.

  1. digz

    digz Guest

    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, Nov 11, 2007
    #1
    1. Advertising

  2. digz

    Kai-Uwe Bux Guest

    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
     
    Kai-Uwe Bux, Nov 11, 2007
    #2
    1. Advertising

  3. digz

    James Kanze Guest

    On Nov 11, 4:00 am, Kai-Uwe Bux <> wrote:
    > 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:
    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
     
    James Kanze, Nov 11, 2007
    #3
  4. digz

    terminator Guest

    On Nov 11, 5:42 am, 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;
    > 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.
     
    terminator, Nov 11, 2007
    #4
  5. digz

    digz Guest

    On Nov 11, 7:36 pm, James Kanze <> wrote:
    > On Nov 11, 4:00 am, Kai-Uwe Bux <> wrote:
    >
    > > 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::eek:perator=(const cacheSType& rhs) {
    if ( &rhs != this )
    {
    cacheSType tmp(rhs);
    std::swap(tmp._cache_t, cache_t);
    data_t = rhs.data_t;
    }
    return *this;
    }
     
    digz, Nov 11, 2007
    #5
  6. digz

    digz Guest

    On Nov 11, 9:54 pm, terminator <> wrote:
    > On Nov 11, 5:42 am, 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;
    > > 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
     
    digz, Nov 11, 2007
    #6
  7. digz

    digz Guest

    On Nov 11, 10:31 pm, digz <> wrote:
    > On Nov 11, 7:36 pm, James Kanze <> wrote:
    >
    >
    >
    >
    >
    > > On Nov 11, 4:00 am, Kai-Uwe Bux <> wrote:

    >
    > > > 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::eek:perator=(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
     
    digz, Nov 11, 2007
    #7
  8. digz

    Kai-Uwe Bux Guest

    digz wrote:

    > On Nov 11, 10:31 pm, digz <> wrote:
    >> On Nov 11, 7:36 pm, James Kanze <> wrote:
    >>
    >>
    >>
    >>
    >>
    >> > On Nov 11, 4:00 am, Kai-Uwe Bux <> wrote:

    >>
    >> > > 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::eek:perator=(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
     
    Kai-Uwe Bux, Nov 11, 2007
    #8
  9. digz

    James Kanze Guest

    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:
    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
     
    James Kanze, Nov 12, 2007
    #9
  10. digz

    Kai-Uwe Bux Guest

    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
     
    Kai-Uwe Bux, Nov 12, 2007
    #10
  11. * 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. ;-)

    Cheers,

    - Alf

    --
    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?
     
    Alf P. Steinbach, Nov 12, 2007
    #11
  12. digz

    Kai-Uwe Bux Guest

    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
     
    Kai-Uwe Bux, Nov 12, 2007
    #12
  13. digz

    Andre Kostur Guest

    "Alf P. Steinbach" <> wrote in
    news::

    > * 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.
     
    Andre Kostur, Nov 12, 2007
    #13
  14. * Kai-Uwe Bux:
    > 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)


    Complete specialization, yes, partial no -- what looks like a partial
    specialization (and what I meant by "specialization" above, using the
    terminology of the article I responded to) is just an overload.

    Andrei Alexandrescu and I think it was Herb Sutter or perhaps it was
    Petru Marginean wrote an article discussing this at length, including
    examples of counter-intuitive effects, available on the net.

    Nothwitstanding that, Pete Becker wrote an article in DDJ about the TR1
    where he used the term "specialization" in the way I/we did above, and
    as I recall also the standard uses this wording in at least one place.


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


    Cheers, -- did you mean "late", or did you mean "early"? :)

    - Alf


    --
    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?
     
    Alf P. Steinbach, Nov 12, 2007
    #14
  15. * Andre Kostur:
    > "Alf P. Steinbach" <> wrote in
    > news::
    >
    >> * 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, but here's an overload of std::swap:

    namespace std
    {
    template< typename T >
    void swap( MyClass<T>& a, MyClass<T> b ) { a.swap( b ); }
    }

    and that's formally ungood.

    Because 17.4.3.1.1 is not much use for function overloads.

    Re the article you responded to, I just wrote with Kai-Uwe in mind,
    forgot this is a public newsgroup. Change "specialization" to
    "overload". Also look up Andrei's article about this if the difference
    isn't clear (why second example above is not a specialization).

    Cheers, & hth.,

    - Alf


    --
    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?
     
    Alf P. Steinbach, Nov 12, 2007
    #15
  16. digz

    James Kanze Guest

    On Nov 12, 12:16 pm, Kai-Uwe Bux <> wrote:
    > 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.


    Not if the code in question wrote std::swap.

    FWIW: my argument that it is "idiomatic" is based on the fact
    that this is what the standard containers are required to do.
    And as far as I know, that isn't changing.

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


    And the current version allows std::sort to use std::swap:).

    Obviously, a swap member function alone doesn't suffice---a
    template designed to work with non-class types as well as class
    types can't use it. A swap member function called by a
    specialization of std::swap will work, and seems the safest
    solution at present. The presence of a swap member function
    makes it quite clear to the reader that your class does support
    a specialized swap. (Of course, if the class is correctly
    documented, that's how the user knows what's what.)

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


    It could be.

    > You are heavily relying on (local) coding conventions should
    > you assume that std::swap is specialized for classes that have
    > a swap member.


    I'm relying mainly on experience with a lot of code from a lot
    of places. I've yet to see a swap member function that invoked
    std::swap( *this, other ).

    > I follow the convention not to use std::swap,


    But others might not. You don't control the code in std::sort.

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


    I know that the issue is being discussed; I don't know what the
    final decision is. Not that it matters; it will be some years
    before I get to use a compiler that is compatible with the next
    version of the standard. (Of the compilers/libraries I
    currently use, two use unqualified swap, one uses std::swap, and
    one does the swap manually (!), so you loose either way you do
    it.)

    --
    James Kanze (GABI Software) email:
    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
     
    James Kanze, Nov 13, 2007
    #16
  17. digz

    James Kanze Guest

    On Nov 12, 2:52 pm, "Alf P. Steinbach" <> wrote:
    > * Andre Kostur:
    > > "Alf P. Steinbach" <> wrote in
    > >news::


    > >> * 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:
    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
     
    James Kanze, Nov 13, 2007
    #17
  18. digz

    Kai-Uwe Bux Guest

    James Kanze wrote:

    > On Nov 12, 12:16 pm, Kai-Uwe Bux <> wrote:
    >> 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.

    >
    > Not if the code in question wrote std::swap.
    >
    > FWIW: my argument that it is "idiomatic" is based on the fact
    > that this is what the standard containers are required to do.
    > And as far as I know, that isn't changing.


    On the other hand, the standard has no place where it makes the existence of
    a swap member function a conceptual requirement. We have to distinguish two
    questions:

    a) Is it advisable to specialize std::swap<> ?
    b) Should the local swap be a member function or a free-standing function?

    I tend to agree with (a) but not with (b).


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

    >
    > And the current version allows std::sort to use std::swap:).
    >
    > Obviously, a swap member function alone doesn't suffice---a
    > template designed to work with non-class types as well as class
    > types can't use it. A swap member function called by a
    > specialization of std::swap will work, and seems the safest
    > solution at present. The presence of a swap member function
    > makes it quite clear to the reader that your class does support
    > a specialized swap. (Of course, if the class is correctly
    > documented, that's how the user knows what's what.)


    Note: specializing std::swap<> and having a swap member function (as opposed
    to a free-standing swap in the ambient namespace) are separate issues. If
    needed, I can still specialize std::swap< my_namespace::my_class > to use
    my_namespace::swap.


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

    >
    > It could be.
    >
    >> You are heavily relying on (local) coding conventions should
    >> you assume that std::swap is specialized for classes that have
    >> a swap member.

    >
    > I'm relying mainly on experience with a lot of code from a lot
    > of places. I've yet to see a swap member function that invoked
    > std::swap( *this, other ).


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

    Note: by saying

    using std::swap;

    and then consistently using unqualified swap(), the code takes advantage of
    any class that is swappable and of any class that specialized std::swap.


    >> I follow the convention not to use std::swap,

    >
    > But others might not. You don't control the code in std::sort.


    See above: specializing std::swap<> is still an option; and you might be
    right to recommend it.


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

    >
    > I know that the issue is being discussed; I don't know what the
    > final decision is. Not that it matters; it will be some years
    > before I get to use a compiler that is compatible with the next
    > version of the standard. (Of the compilers/libraries I
    > currently use, two use unqualified swap, one uses std::swap, and
    > one does the swap manually (!), so you loose either way you do
    > it.)


    Nice data points.


    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Nov 13, 2007
    #18
  19. digz

    James Kanze Guest

    On Nov 13, 11:30 am, Kai-Uwe Bux <> wrote:
    > James Kanze wrote:
    > > On Nov 12, 12:16 pm, Kai-Uwe Bux <> wrote:
    > >> James Kanze wrote:
    > >> > Kai-Uwe Bux wrote:


    > >> > [...]

    > > FWIW: my argument that it is "idiomatic" is based on the fact
    > > that this is what the standard containers are required to do.
    > > And as far as I know, that isn't changing.


    > On the other hand, the standard has no place where it makes
    > the existence of a swap member function a conceptual
    > requirement.


    > We have to distinguish two questions:


    > a) Is it advisable to specialize std::swap<> ?
    > b) Should the local swap be a member function or a free-standing function?


    > I tend to agree with (a) but not with (b).


    Just curious, but why not? (Although it's an interesting
    question. As a general rule, std::swap is defined to have the
    semantics I want, an otherwise visible swap theoretically might
    not (although I can't imagine anything else swap could mean off
    hand). So I would normally have automatically used std::swap
    everywhere. The standard seems to be going in the other
    direction, however: requiring that the call to swap in the
    library not be qualified (and thus that it might pick up a swap
    with other semantics---or rather, indirectly, that any function
    named swap must have the semantics specified by the standard,
    regardless of what namespace it is in).

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


    > > And the current version allows std::sort to use std::swap:).


    > > Obviously, a swap member function alone doesn't suffice---a
    > > template designed to work with non-class types as well as class
    > > types can't use it. A swap member function called by a
    > > specialization of std::swap will work, and seems the safest
    > > solution at present. The presence of a swap member function
    > > makes it quite clear to the reader that your class does support
    > > a specialized swap. (Of course, if the class is correctly
    > > documented, that's how the user knows what's what.)


    > Note: specializing std::swap<> and having a swap member
    > function (as opposed to a free-standing swap in the ambient
    > namespace) are separate issues.


    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.

    Given the variation in practice here, that seems to be the
    safest.

    Note that my convention is more or less an adaptation to the all
    to frequent case of poor documentation. My experience has been
    that programmers don't provide a member function swap unless
    they are aware of the swap idiom, and providing for it. So it's
    presence is a strong indication of something that really should
    be documented. If your class documentation otherwise specifies
    that the class supports the swap idiom by means of a global
    function, that's fine too. (If you're using something like
    Doxygen, it's probably easier to document the member function,
    and have the documentation show up in the right place. This is
    probably best considered a weakness of Doxygen---or of my
    knowledge of Doxygen---but it doesn't associate free functions
    with the relevant class.)

    [...]
    > > I'm relying mainly on experience with a lot of code from a lot
    > > of places. I've yet to see a swap member function that invoked
    > > std::swap( *this, other ).


    > 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.
    It's nothing cast in stone, but it happens to be the strategy
    which seems to work best with the code I've actually seen, and
    had to deal with. (In the meantime, I think I will take to
    adding a local overload of swap as well. No point in not
    covering all bases.)

    --
    James Kanze (GABI Software) email:
    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
     
    James Kanze, Nov 14, 2007
    #19
  20. digz

    Kai-Uwe Bux Guest

    James Kanze wrote:

    > On Nov 13, 11:30 am, Kai-Uwe Bux <> wrote:
    >> James Kanze wrote:
    >> > On Nov 12, 12:16 pm, Kai-Uwe Bux <> wrote:
    >> >> James Kanze wrote:
    >> >> > Kai-Uwe Bux wrote:

    >
    >> >> > [...]
    >> > FWIW: my argument that it is "idiomatic" is based on the fact
    >> > that this is what the standard containers are required to do.
    >> > And as far as I know, that isn't changing.

    >
    >> On the other hand, the standard has no place where it makes
    >> the existence of a swap member function a conceptual
    >> requirement.

    >
    >> We have to distinguish two questions:

    >
    >> a) Is it advisable to specialize std::swap<> ?
    >> b) Should the local swap be a member function or a free-standing
    >> function?

    >
    >> I tend to agree with (a) but not with (b).

    >
    > Just curious, but why not?


    Ah, that goes back to the hassles that I called upon me when I tried to
    write generic code that would _call_ the right swap for each type. To see
    the problem, recall that there are (at least) three ways for a type T to
    provide a specialized swap:

    a) specialize std::swap<>
    b) define a swap member function
    c) define a free-standing swap (presumably a friend)

    Now, when I write my template code based on T, how should I do a swap? I can
    take care of (a) and (c) in one swoop by making std::swap visible in my
    namespace. The swap from the namespace of T will be visible through ADL.
    But, how should I take care of the member functions? I tried this: use
    template magic to detect a swap member. However, it turned out to be a
    royal pain because I it turned swap into something ambiguous. In the end, I
    had to write

    call_swap( lhs, rhs );

    in my own code instead of swap just so that call_swap() would magically
    resolve to the right thing. At that point, I decided that it isn't worth
    the effort to support all three conventions. Since a) and c) are the
    easiest to support simultaneously, I went with that.

    Another reason is my own lazyness. If I do:

    template < typename T >
    class X {

    T member;

    void swap ( X & other ) {
    swap( this->member, other.member );
    ...
    }

    };

    I run into the issue that the local swap member hides the identifier for the
    swap function that is being called. Since I want the swap call to resolve
    correctly, and since I am dealing with a templated type, I cannot just go
    on an put a namespace qualification.

    If I do:

    template < typename T >
    class X {

    T member;

    friend
    void swap ( X & lhs, X & rhs ) {
    swap ( lhs.member, rhs.member );
    }

    };

    the issue does not come up.


    In short, I found that in template code (which is most of what I do), the
    convention (c) is the easiest to deal with.


    > (Although it's an interesting
    > question. As a general rule, std::swap is defined to have the
    > semantics I want, an otherwise visible swap theoretically might
    > not (although I can't imagine anything else swap could mean off
    > hand). So I would normally have automatically used std::swap
    > everywhere. The standard seems to be going in the other
    > direction, however: requiring that the call to swap in the
    > library not be qualified (and thus that it might pick up a swap
    > with other semantics---or rather, indirectly, that any function
    > named swap must have the semantics specified by the standard,
    > regardless of what namespace it is in).


    Yup that seems to be the direction of the standard. I wholeheartly agree
    with that :)


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

    >
    >> > And the current version allows std::sort to use std::swap:).

    >
    >> > Obviously, a swap member function alone doesn't suffice---a
    >> > template designed to work with non-class types as well as class
    >> > types can't use it. A swap member function called by a
    >> > specialization of std::swap will work, and seems the safest
    >> > solution at present. The presence of a swap member function
    >> > makes it quite clear to the reader that your class does support
    >> > a specialized swap. (Of course, if the class is correctly
    >> > documented, that's how the user knows what's what.)

    >
    >> Note: specializing std::swap<> and having a swap member
    >> function (as opposed to a free-standing swap in the ambient
    >> namespace) are separate issues.

    >
    > 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.
    >
    > Given the variation in practice here, that seems to be the
    > safest.


    Probably.


    > Note that my convention is more or less an adaptation to the all
    > to frequent case of poor documentation. My experience has been
    > that programmers don't provide a member function swap unless
    > they are aware of the swap idiom, and providing for it. So it's
    > presence is a strong indication of something that really should
    > be documented. If your class documentation otherwise specifies
    > that the class supports the swap idiom by means of a global
    > function, that's fine too. (If you're using something like
    > Doxygen, it's probably easier to document the member function,
    > and have the documentation show up in the right place. This is
    > probably best considered a weakness of Doxygen---or of my
    > knowledge of Doxygen---but it doesn't associate free functions
    > with the relevant class.)


    Right: freestanding swap functions are clearly part of the class interface
    and need to be documented as such.

    On a related note: generic libraries should clearly document whether they
    require a type to have a swap member function, be swappable, or use a
    specialized std::swap.

    > [...]
    >> > I'm relying mainly on experience with a lot of code from a lot
    >> > of places. I've yet to see a swap member function that invoked
    >> > std::swap( *this, other ).

    >
    >> 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. I can see, however, that it is probably the most
    convenient for you (and it makes the least assumptions).

    > It's nothing cast in stone, but it happens to be the strategy
    > which seems to work best with the code I've actually seen, and
    > had to deal with. (In the meantime, I think I will take to
    > adding a local overload of swap as well. No point in not
    > covering all bases.)


    Yup.


    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Nov 14, 2007
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    1,193
  2. Gabriel Rossetti
    Replies:
    0
    Views:
    1,388
    Gabriel Rossetti
    Aug 29, 2008
  3. siddhu
    Replies:
    5
    Views:
    824
    Michael Doubez
    May 18, 2011
  4. Replies:
    1
    Views:
    373
    Brian Candler
    Aug 12, 2003
  5. Aredridel

    Not just $SAFE, but damn $SAFE

    Aredridel, Sep 2, 2004, in forum: Ruby
    Replies:
    19
    Views:
    263
Loading...

Share This Page