no-fail swap for char []'s

Discussion in 'C++' started by Dennis Jones, Jan 17, 2008.

  1. Dennis Jones

    Dennis Jones Guest

    Hi all,

    1) Let's say you have two char []'s of the same size. How would you write a
    no-fail swap method for them? For example:

    class Test
    {
    char s[10];
    void swap( Test &rhs )
    {
    // is it possible to swap the data member 's' with the no-fail
    guarantee?
    }
    };


    2) If the data member is a pointer (char *), is std::swap sufficient (even
    if the other pointer was allocated with a different size)? For example:

    class Test
    {
    char *s; // assume this is allocated to some size
    void swap( Test &rhs )
    {
    std::swap( s, rhs.s ); // is this okay?
    }
    };

    Thanks,

    - Dennis
     
    Dennis Jones, Jan 17, 2008
    #1
    1. Advertising

  2. Dennis Jones

    Dennis Jones Guest

    "Dennis Jones" <> wrote in message
    news:6Jxjj.17776$Y63.13879@trnddc03...
    > Hi all,
    >
    > 1) Let's say you have two char []'s of the same size. How would you write
    > a no-fail swap method for them? For example:
    >
    > class Test
    > {
    > char s[10];
    > void swap( Test &rhs )
    > {
    > // is it possible to swap the data member 's' with the no-fail
    > guarantee?
    > }
    > };


    Well, after thinking about it for a few minutes, I came up with this:

    void strswap( char * const c1, char * const c2 )
    {
    int size = std::max( strlen(c1), strlen(c2) ) + 1;
    for ( int c=0; c<size; ++c )
    {
    std::swap( c1[c], c2[c] );
    }
    }

    class Test
    {
    char s[10]; // guaranteed to be a valid string
    void swap( Test &rhs )
    {
    strswap( s, rhs.s );
    }
    };

    Is this reasonable?

    - Dennis
     
    Dennis Jones, Jan 17, 2008
    #2
    1. Advertising

  3. * Dennis Jones:
    > "Dennis Jones" <> wrote in message
    > news:6Jxjj.17776$Y63.13879@trnddc03...
    >> Hi all,
    >>
    >> 1) Let's say you have two char []'s of the same size. How would you write
    >> a no-fail swap method for them? For example:
    >>
    >> class Test
    >> {
    >> char s[10];
    >> void swap( Test &rhs )
    >> {
    >> // is it possible to swap the data member 's' with the no-fail
    >> guarantee?
    >> }
    >> };

    >
    > Well, after thinking about it for a few minutes, I came up with this:
    >
    > void strswap( char * const c1, char * const c2 )
    > {
    > int size = std::max( strlen(c1), strlen(c2) ) + 1;
    > for ( int c=0; c<size; ++c )
    > {
    > std::swap( c1[c], c2[c] );
    > }
    > }


    The questions you posed looked like homework.

    But since you now have made an effort:

    It was not specified that the arrays contained nullterminated strings,
    hence std::strlen is contra-indicated. It was specified that the arrays
    were of the same size, hence std::max is contra-indicated.



    > class Test
    > {
    > char s[10]; // guaranteed to be a valid string
    > void swap( Test &rhs )
    > {
    > strswap( s, rhs.s );
    > }
    > };
    >
    > Is this reasonable?


    No.

    For the in-practice of providing swappable strings, use std::string.


    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, Jan 17, 2008
    #3
  4. Dennis Jones

    Dennis Jones Guest

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

    >> Well, after thinking about it for a few minutes, I came up with this:
    >>
    >> void strswap( char * const c1, char * const c2 )
    >> {
    >> int size = std::max( strlen(c1), strlen(c2) ) + 1;
    >> for ( int c=0; c<size; ++c )
    >> {
    >> std::swap( c1[c], c2[c] );
    >> }
    >> }

    >
    > The questions you posed looked like homework.


    Hi Alf, I was hoping you or Victor would respond!

    No. I am a professional, though I do work from home, so I guess you *could*
    call it homework! But it is NOT schoolwork. The example code I provided is
    just to demonstrate what I would like to do in an existing application to
    improve the reliability of the existing code and the strswap() function
    therein (which is awful):

    void strswap( char * const c1, char * const c2 )
    {
    char *temp = strdup( c1 );
    strcpy( c1, c2 );
    strcpy( c2, temp );
    free( temp );
    }


    > But since you now have made an effort:
    >
    > It was not specified that the arrays contained nullterminated strings,


    I added the "// guaranteed to be a valid string" comment to indicate that
    they are null-terminated (I know, I didn't say so in my first post). The
    classes all have constructors which guarantee that the members are either
    initialized to zero, or otherwise initialized to a valid string.


    > hence std::strlen is contra-indicated.


    I understand your point, but they *will* be null-terminated.


    > It was specified that the arrays were of the same size, hence std::max is
    > contra-indicated.


    I understand your point here too. The purpose of using strlen and max was
    to determine the minimum number of characters I could swap and not lose any
    data. There's no point in swapping the entire content of the arrays if they
    don't need to be.

    Now, if I were to explicitly do the work in the swap member function, then I
    *could* do:

    class Test
    {
    char s[10];
    void swap( Test &rhs )
    {
    for ( int i=0; i<sizeof(s)/sizeof(s[0]); ++i )
    {
    std::swap( s, rhs.s );
    }
    }
    };

    That does avoid the extra strlen and max calls (which might affect the
    efficiency of the function). However, I would prefer not to have to
    re-write the same thing over and over in many different classes that contain
    many char[] data members (DRY principle), which is why I wrote the
    standalone strswap() function [so I wouldn't have to write the same code
    over and over for every char[] data member in every class -- that would be
    ridiculous!!].

    So, for something that is re-usable, I opted for a standalone function. To
    be generic enough to use it with any of the char[] data members in all those
    classes, it was necessary to loop based on the data itself. Though, I
    suppose I could also do:

    void strswap( char * const c1, char * const c2, size_t length )
    {
    for ( int i=0; i<length; ++i )
    {
    std::swap( c1, c2 );
    }
    }

    class Test
    {
    char s[C]; // where C is some constant
    void swap( Test &rhs )
    {
    strswap( s, rhs.s, sizeof(s)/sizeof(s[0]) );
    }
    };


    > For the in-practice of providing swappable strings, use std::string.


    I do use std::string (actually a variant of it) with newer code, but I don't
    have that option here (not without a LOT of re-writing) because this is very
    old, legacy code.

    All of the examples do the same basic thing, and that is to swap the
    contents of two char arrays. My question isn't whether or not strlen or max
    is contra-indicated, as if it were a homework assignment. My question is,
    how do I provide the no-fail guarantee when swapping an array of 'sometype'
    (we might just as well be talking about an array of any type)?

    So, to be more specific, is a loop a satisfactory way to swap array elements
    and still provide the no-fail guarantee? I can't think of any other way --
    can you?

    - Dennis
     
    Dennis Jones, Jan 17, 2008
    #4
  5. Dennis Jones

    Barry Guest

    Dennis Jones wrote:
    > "Alf P. Steinbach" <> wrote in message
    > news:...
    >
    >>> Well, after thinking about it for a few minutes, I came up with this:
    >>>
    >>> void strswap( char * const c1, char * const c2 )
    >>> {
    >>> int size = std::max( strlen(c1), strlen(c2) ) + 1;
    >>> for ( int c=0; c<size; ++c )
    >>> {
    >>> std::swap( c1[c], c2[c] );
    >>> }
    >>> }

    >> The questions you posed looked like homework.

    >
    > Hi Alf, I was hoping you or Victor would respond!
    >
    > No. I am a professional, though I do work from home, so I guess you *could*
    > call it homework! But it is NOT schoolwork. The example code I provided is
    > just to demonstrate what I would like to do in an existing application to
    > improve the reliability of the existing code and the strswap() function
    > therein (which is awful):
    >
    > void strswap( char * const c1, char * const c2 )
    > {
    > char *temp = strdup( c1 );
    > strcpy( c1, c2 );
    > strcpy( c2, temp );
    > free( temp );
    > }


    the std::swap in algorithm requires the type to be Assignable,
    so with /char*/, you can simply use std::swap.

    while array is not Assignable, so you have to do the extra job as you
    did above.

    >
    >
    >> But since you now have made an effort:
    >>
    >> It was not specified that the arrays contained nullterminated strings,

    >
    > I added the "// guaranteed to be a valid string" comment to indicate that
    > they are null-terminated (I know, I didn't say so in my first post). The
    > classes all have constructors which guarantee that the members are either
    > initialized to zero, or otherwise initialized to a valid string.
    >
    >
    >> hence std::strlen is contra-indicated.

    >
    > I understand your point, but they *will* be null-terminated.
    >
    >
    >> It was specified that the arrays were of the same size, hence std::max is
    >> contra-indicated.

    >
    > I understand your point here too. The purpose of using strlen and max was
    > to determine the minimum number of characters I could swap and not lose any
    > data. There's no point in swapping the entire content of the arrays if they
    > don't need to be.
    >
    > Now, if I were to explicitly do the work in the swap member function, then I
    > *could* do:
    >
    > class Test
    > {
    > char s[10];
    > void swap( Test &rhs )
    > {
    > for ( int i=0; i<sizeof(s)/sizeof(s[0]); ++i )
    > {
    > std::swap( s, rhs.s );
    > }


    the for loop can be replaced by std::swap_ranges

    std::swap_ranges(s, s + sizeof(s)/sizeof(s[0]), rhs.s);

    > }
    > };
    >
    > That does avoid the extra strlen and max calls (which might affect the
    > efficiency of the function). However, I would prefer not to have to
    > re-write the same thing over and over in many different classes that contain
    > many char[] data members (DRY principle), which is why I wrote the
    > standalone strswap() function [so I wouldn't have to write the same code
    > over and over for every char[] data member in every class -- that would be
    > ridiculous!!].
    >
    > So, for something that is re-usable, I opted for a standalone function. To
    > be generic enough to use it with any of the char[] data members in all those
    > classes, it was necessary to loop based on the data itself. Though, I
    > suppose I could also do:
    >
    > void strswap( char * const c1, char * const c2, size_t length )
    > {
    > for ( int i=0; i<length; ++i )
    > {
    > std::swap( c1, c2 );
    > }
    > }
    >
    > class Test
    > {
    > char s[C]; // where C is some constant
    > void swap( Test &rhs )
    > {
    > strswap( s, rhs.s, sizeof(s)/sizeof(s[0]) );
    > }
    > };
    >
    >
    >> For the in-practice of providing swappable strings, use std::string.

    >
    > I do use std::string (actually a variant of it) with newer code, but I don't
    > have that option here (not without a LOT of re-writing) because this is very
    > old, legacy code.
    >
    > All of the examples do the same basic thing, and that is to swap the
    > contents of two char arrays. My question isn't whether or not strlen or max
    > is contra-indicated, as if it were a homework assignment. My question is,
    > how do I provide the no-fail guarantee when swapping an array of 'sometype'
    > (we might just as well be talking about an array of any type)?
    >
    > So, to be more specific, is a loop a satisfactory way to swap array elements
    > and still provide the no-fail guarantee? I can't think of any other way --


    I guess you meant "no throw guarantee",
    the answer is Yes

    > can you?



    --
    Thanks
    Barry
     
    Barry, Jan 17, 2008
    #5
  6. Dennis Jones wrote:
    > [..]
    > Now, if I were to explicitly do the work in the swap member function,
    > then I *could* do:
    >
    > class Test
    > {
    > char s[10];
    > void swap( Test &rhs )
    > {
    > for ( int i=0; i<sizeof(s)/sizeof(s[0]); ++i )
    > {
    > std::swap( s, rhs.s );
    > }
    > }
    > };
    >
    > That does avoid the extra strlen and max calls (which might affect the
    > efficiency of the function). However, I would prefer not to have to
    > re-write the same thing over and over in many different classes that
    > contain many char[] data members (DRY principle), which is why I
    > wrote the standalone strswap() function [so I wouldn't have to write
    > the same code over and over for every char[] data member in every
    > class -- that would be ridiculous!!].
    > [..]


    Make it a template, something like

    template<unsigned s> void strswap(char (&a1), char (&a2))
    {
    for (unsigned i = s; i-- > 0; )
    std::swap(a1, a2);
    }

    and reuse it inside 'swap' function in each class that has a char[]
    member.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jan 17, 2008
    #6
  7. Dennis Jones

    Dennis Jones Guest

    "Barry" <> wrote in message
    news:fmmqdd$896$99.com...

    > the std::swap in algorithm requires the type to be Assignable,
    > so with /char*/, you can simply use std::swap.


    Thanks, I pretty much figured that one out.


    > while array is not Assignable, so you have to do the extra job as you did
    > above.


    Thank you.


    > the for loop can be replaced by std::swap_ranges
    >
    > std::swap_ranges(s, s + sizeof(s)/sizeof(s[0]), rhs.s);
    >
    >> }
    >> };


    Good point. There are so many algorithms, it's easy to forget what's
    available.


    > I guess you meant "no throw guarantee",
    > the answer is Yes


    No, I mean "no-fail," as mentioned in Sutter & Alexandrescu's "C++ Coding
    Standards", items 51 & 56.

    Thanks for the feedback and confirmation.

    - Dennis
     
    Dennis Jones, Jan 17, 2008
    #7
  8. Dennis Jones

    Dennis Jones Guest

    "Victor Bazarov" <> wrote in message
    news:...

    > Make it a template, something like
    >
    > template<unsigned s> void strswap(char (&a1), char (&a2))
    > {
    > for (unsigned i = s; i-- > 0; )
    > std::swap(a1, a2);
    > }


    You know Victor, I was wondering if there was a nice way to do it with a
    template. Okay, so let's say I use your template and do this:

    class Test
    {
    char str[10];
    void swap( Test &rhs )
    {
    strswap( str, rhs.str );
    }
    };

    I am not very familiar with that syntax. You are using 's' as a value,
    rather than a type. But since the size of the array is known at
    compile-time, I presume then that the compiler is able to interpret the
    value of 's' based on the argument(s) passed to it? If so, that's pretty
    cool!

    - Dennis
     
    Dennis Jones, Jan 17, 2008
    #8
  9. Dennis Jones

    Dennis Jones Guest

    "Victor Bazarov" <> wrote in message
    news:...
    >
    > Make it a template, something like
    >
    > template<unsigned s> void strswap(char (&a1), char (&a2))
    > {
    > for (unsigned i = s; i-- > 0; )
    > std::swap(a1, a2);
    > }


    Shoot. Unfortunately, my compiler, doesn't like this. It gives the error:

    "Could not find a match for 'strswap<s>(char *,char *)'"

    Here is the test code I tried:

    #include <algorithm>

    template<unsigned s>
    void strswap(char (&a1), char (&a2))
    {
    for (unsigned i = s; i-- > 0; )
    std::swap(a1, a2);
    }

    class Test
    {
    public:
    char str[10];
    void swap( Test &rhs )
    {
    strswap( str, rhs.str );
    // strswap<10>( str, rhs.str ); // I tried this, thinking maybe I needed
    to specify the value of 's'
    }
    };

    int main(int argc, char* argv[])
    {
    Test t1, t2;
    strcpy( t1.str, "hello" );
    strcpy( t2.str, "world" );
    t1.swap( t2 );
    return 0;
    }

    So, either:

    1) The compiler doesn't support this template usage (I tried BCB5, BCB6,
    BDS2006 and CRS2007 -- all give the same error).
    2) I am not using it correctly.

    Since it didn't work in any of my compilers, I'm betting my usage is
    incorrect. Can you enlighten me?

    - Dennis
     
    Dennis Jones, Jan 17, 2008
    #9
  10. Dennis Jones

    Dennis Jones Guest

    "Dennis Jones" <> wrote in message
    news:AiCjj.17814$Y63.13798@trnddc03...

    > Shoot. Unfortunately, my compiler, doesn't like this. It gives the
    > error:
    >
    > "Could not find a match for 'strswap<s>(char *,char *)'"


    A couple of changes got it to work:

    template<unsigned s>
    void strswap(char (a1), char (a2)) // removed the '&'s
    {
    for (unsigned i = s; i-- > 0; )
    std::swap(a1, a2);
    }

    class Test
    {
    public:
    char str[10];
    void swap( Test &rhs )
    {
    strswap<10>( str, rhs.str ); // added the "<10>"
    }
    };

    So, apparently, the compiler *cannot* deduce 's' at compile-time (or I'm
    still doing something wrong).

    - Dennis
     
    Dennis Jones, Jan 17, 2008
    #10
  11. * Dennis Jones:
    > "Victor Bazarov" <> wrote in message
    > news:...
    >> Make it a template, something like
    >>
    >> template<unsigned s> void strswap(char (&a1), char (&a2))
    >> {
    >> for (unsigned i = s; i-- > 0; )
    >> std::swap(a1, a2);
    >> }

    >
    > Shoot. Unfortunately, my compiler, doesn't like this. It gives the error:
    >
    > "Could not find a match for 'strswap<s>(char *,char *)'"
    >
    > Here is the test code I tried:
    >
    > #include <algorithm>
    >
    > template<unsigned s>
    > void strswap(char (&a1), char (&a2))
    > {
    > for (unsigned i = s; i-- > 0; )
    > std::swap(a1, a2);
    > }
    >
    > class Test
    > {
    > public:
    > char str[10];
    > void swap( Test &rhs )
    > {
    > strswap( str, rhs.str );
    > // strswap<10>( str, rhs.str ); // I tried this, thinking maybe I needed
    > to specify the value of 's'
    > }
    > };
    >
    > int main(int argc, char* argv[])
    > {
    > Test t1, t2;
    > strcpy( t1.str, "hello" );
    > strcpy( t2.str, "world" );
    > t1.swap( t2 );
    > return 0;
    > }
    >
    > So, either:
    >
    > 1) The compiler doesn't support this template usage (I tried BCB5, BCB6,
    > BDS2006 and CRS2007 -- all give the same error).


    Compiles fine with MSVC7.1, g++ 3.4.4 and Comeau Online 4.3.9.

    Especially the last indicates the code is OK at the level of
    compiles-or-not.

    Borland 5 (if that's BCB5) is pretty old. I don't know the other
    compilers you've listed. Googling it seems the last is an IDE.


    > 2) I am not using it correctly.
    >
    > Since it didn't work in any of my compilers, I'm betting my usage is
    > incorrect. Can you enlighten me?


    Try a modern / non-Borland compiler?


    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, Jan 17, 2008
    #11
  12. Dennis Jones

    Dennis Jones Guest

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

    >> 1) The compiler doesn't support this template usage (I tried BCB5, BCB6,
    >> BDS2006 and CRS2007 -- all give the same error).

    >
    > Compiles fine with MSVC7.1, g++ 3.4.4 and Comeau Online 4.3.9.
    >
    > Especially the last indicates the code is OK at the level of
    > compiles-or-not.
    >
    > Borland 5 (if that's BCB5) is pretty old. I don't know the other
    > compilers you've listed. Googling it seems the last is an IDE.



    They're all IDE's, but they all include command-line versions of the
    compiler, linker, make, etc.


    >
    > Try a modern / non-Borland compiler?



    BCB5 (Borland C++Builder version 5) and Borland C++ 5.0x are NOT the same
    product. Borland C++ 5.0x was circa 1997. BCB5 came out in 2000. BCB6
    came out in 2002, BDS2006 (Borland Developer Studio) in 2006, and CRS2007
    (CodeGear RAD Studio) in 2007. So, they are all relatively "modern"
    compilers.

    Borland *used* to be known for its standards compliance (back in the early
    90's). They aren't so much anymore, but they (now CodeGear, which split off
    from Borland last year) are working hard (they better be, darn it!) to
    improve compliance in their latest compiler (C++Builder 2007). For example,
    being able to build as many of the Boost libraries as possible (Spirit, for
    instance) is one of the areas they are focusing on. The latest product
    includes the Dinkumware library, and I don't think any of their previous
    compilers would have worked with Dinkumware -- so they are making progress.

    Anyway, for now, I've settled on the following:

    void strswap( char *c1, char *c2 )
    {
    const int size = std::max( strlen(c1), strlen(c2) ) + 1;
    std::swap_ranges( c1, c1+size, c2 );
    }

    This allows me to benefit from a no-fail swap without having to change any
    of the dozens of existing classes that already use it. If I could get
    Victor's template version to work without having to specify the array size
    (e.g. strswap<N>), I would have preferred that, but since I can't (not
    without changing every strswap call), I think my current version is
    adequate.

    I had to remove 'const' from the pointer parameters because there is some
    *really* old code that is still compiled by the 1997 version of the compiler
    (which uses an old, buggy STL implementation -- HP/RogueWave, I think), and
    its version of swap_ranges wouldn't work with 'const' pointers. Oh well.

    Thanks Alf, Barry, and Victor for your help,

    - Dennis
     
    Dennis Jones, Jan 17, 2008
    #12
  13. Dennis Jones

    Dennis Jones Guest

    "Dennis Jones" <> wrote in message
    news:nsDjj.11566$cz3.4686@trnddc06...
    >
    > I had to remove 'const' from the pointer parameters because there is some
    > *really* old code that is still compiled by the 1997 version of the
    > compiler (which uses an old, buggy STL implementation -- HP/RogueWave, I
    > think), and its version of swap_ranges wouldn't work with 'const'
    > pointers. Oh well.


    I take that back. I can use const_cast<char*> to work around the
    HP/RogueWave bug.

    - Dennis
     
    Dennis Jones, Jan 17, 2008
    #13
  14. Dennis Jones

    Dennis Jones Guest

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

    > Try a modern / non-Borland compiler?


    Or, report the bug and ask the vendor to fix it.

    As it turns out, the bug (cannot convert from char[] to char(&)[], but
    converts to char * instead) only exists for non-static data members.
    Non-members and static data members both work fine. Unfortunately, I need
    non-static members to work or I can't use the template function in my swap
    routine! The vendor (CodeGear) has opened a ticket for the bug and will be
    addressing it. Even if that does me no good at the moment, it's a good
    sign.

    - Dennis
     
    Dennis Jones, Jan 19, 2008
    #14
    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. Wenjie

    if (f() != FAIL) or if (FAIL != f())?

    Wenjie, Jul 28, 2003, in forum: C Programming
    Replies:
    3
    Views:
    450
    E. Robert Tisdale
    Jul 31, 2003
  2. lovecreatesbeauty
    Replies:
    1
    Views:
    1,056
    Ian Collins
    May 9, 2006
  3. dbuser
    Replies:
    5
    Views:
    1,827
    Default User
    Oct 11, 2005
  4. Niels Dekker (no reply address)

    What swap is called when using std::swap?

    Niels Dekker (no reply address), Jul 19, 2006, in forum: C++
    Replies:
    4
    Views:
    991
    Niels Dekker (no reply address)
    Jul 20, 2006
  5. NK

    swap char array.

    NK, Dec 26, 2007, in forum: C++
    Replies:
    3
    Views:
    567
    tragomaskhalos
    Dec 27, 2007
Loading...

Share This Page