473,382 Members | 1,387 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,382 software developers and data experts.

no-fail swap for char []'s

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
Jan 17 '08 #1
11 2897

"Dennis Jones" <no****@nospam.comwrote 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
Jan 17 '08 #2

"Alf P. Steinbach" <al***@start.nowrote in message
news:13*************@corp.supernews.com...
>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[i], rhs.s[i] );
}
}
};

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[i], c2[i] );
}
}

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
Jan 17 '08 #3
Dennis Jones wrote:
"Alf P. Steinbach" <al***@start.nowrote in message
news:13*************@corp.supernews.com...
>>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[i], rhs.s[i] );
}
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[i], c2[i] );
}
}

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
Jan 17 '08 #4
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[i], rhs.s[i] );
}
}
};

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 svoid strswap(char (&a1)[s], char (&a2)[s])
{
for (unsigned i = s; i-- 0; )
std::swap(a1[i], a2[i]);
}

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
Jan 17 '08 #5

"Barry" <dh*****@gmail.comwrote in message
news:fm**********@news.cn99.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
Jan 17 '08 #6

"Victor Bazarov" <v.********@comAcast.netwrote in message
news:CY******************************@comcast.com. ..
Make it a template, something like

template<unsigned svoid strswap(char (&a1)[s], char (&a2)[s])
{
for (unsigned i = s; i-- 0; )
std::swap(a1[i], a2[i]);
}
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
Jan 17 '08 #7

"Victor Bazarov" <v.********@comAcast.netwrote in message
news:CY******************************@comcast.com. ..
>
Make it a template, something like

template<unsigned svoid strswap(char (&a1)[s], char (&a2)[s])
{
for (unsigned i = s; i-- 0; )
std::swap(a1[i], a2[i]);
}
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)[s], char (&a2)[s])
{
for (unsigned i = s; i-- 0; )
std::swap(a1[i], a2[i]);
}

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
Jan 17 '08 #8

"Dennis Jones" <no****@nospam.comwrote 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)[s], char (a2)[s]) // removed the '&'s
{
for (unsigned i = s; i-- 0; )
std::swap(a1[i], a2[i]);
}

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
Jan 17 '08 #9

"Alf P. Steinbach" <al***@start.nowrote in message
news:13*************@corp.supernews.com...
>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
Jan 17 '08 #10

"Dennis Jones" <no****@nospam.comwrote 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
Jan 17 '08 #11

"Alf P. Steinbach" <al***@start.nowrote in message
news:13*************@corp.supernews.com...
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
Jan 19 '08 #12

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

Similar topics

38
by: JKop | last post by:
union SignedChoice{ long with_sign; unsigned long without_sign; }; int main() { SignedChoice data;
5
by: dbuser | last post by:
Hi, I have to implement every even and odd character swapping of a stream. My problem is with the following code is that if the stream has total even no of characters in it(including spaces) then...
14
by: Otto Meijer | last post by:
Hi everyone, for one of my projects I need to figure out the size of the swap file(s) of a certain system. The problem is I need to do this on a host of platforms like: HP_UX, Solaris, Linux,...
8
by: meendar | last post by:
This is my program on swap of strings.i just used pointer for swapping the string. can anyone help me why it is not working? #include<iostream.h> #include<string.h> void swap(char *char1,...
1
by: bob | last post by:
let's say you want a function to swap pointers. is this how you take two pointers by reference: void swap(char* &p1, char* &p2);
9
by: ma740988 | last post by:
Consider: # include <vector> # include <iostream> # include <cstdlib> # include <ctime> bool ispow2i ( double n ) {
5
by: Bo Berglund | last post by:
Preamble: I am a Delphi (Pascal) programmer who has stumbled into the C++ world by necessity since Borland has no 64 bit compiler yet out.... I used to do a lot of ANSI C programming for embedded...
3
by: NK | last post by:
char *a="nnnnnnn fgjfjgjf"; char *b="ABC jjjjjjjjjhhhh"; to swap these two string...... this swap fn is working template<class T> void Swap( const T *&a,const T *&b)//no need to write...
20
by: sirsnorklingtayo | last post by:
hi guys please help about Linked List, I'm having trouble freeing the allocated memory of a single linked list node with a dynamic char* fields, it doesn't freed up if I use the FREE()...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...

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.