Reputation:
The following code was produced by a consultant working for my group. I'm not a C++ developer (worked in many languages, though) but would like some independent opinions on the following code. This is in Visual Studio C++ 6.0. I've got a gut reaction (not a good one, obviously), but I'd like some "gut reactions" from seasoned (or even not so unseasoned) C++ developers out there. Thanks in advance!
// Example call
strColHeader = insert_escape(strColHeader, ',', '\\'); //Get rid of the commas and make it an escape character
...snip...
CString insert_escape ( CString originalString, char charFind, char charInsert ) {
bool continueLoop = true;
int currentInd = 0;
do {
int occurenceInd = originalString.Find(charFind, currentInd);
if(occurenceInd>0) {
originalString.Insert(occurenceInd, charInsert);
currentInd = occurenceInd + 2;
}
else {
continueLoop = false;
}
} while(continueLoop);
return(originalString);
}
Upvotes: 6
Views: 1481
Reputation: 48290
Is this consultant being paid by the line of code? Several folks have pointed out that the CString
class already provides this functionality, so even if you're not a programmer, you know:
CString
function probably works and is probably efficient; this one may or may not be.CString
function is documented, and is therefore supportable.CString
function or thought he/she could do better by writing a new one.
And perhaps the biggest, reddest flag of all: your instincts prodded you to get opinions from the StackOverflow community.
Trust your instincts.
Upvotes: 1
Reputation: 83309
I won't provide an alternative code, as it would only add to the code already provided.
But, my gut feeling is that there's something wrong with the code.
To prove it, I will enumerate some points in the original function that shows its developer was not an experienced C++ developer, points that you should investigate if you need a clean implementation:
Upvotes: 2
Reputation: 45493
There's an off-by-one bug sitting there right in the middle: Take a look at what happens if the first character is a comma: ",abc,def,ghi": I'm assuming the desired output would be "\,abc\,def\,ghi", but instead you get the original string back:
int occurenceInd = originalString.Find(charFind, currentInd);
OccurrenceInd returns 0, since it found charFind at the first character.
if(occurenceInd>0)
0 isn't greater than 0, so take the else branch and return the original string. CString::Find returns -1 when it can't find something, so at the very least that comparison should be:
if(occurrenceInd >= 0)
The best way would be to use the Replace function, but if you want to do it by hand, a better implementation would probably look something like this:
CString insert_escape ( const CString &originalString, char charFind, char charInsert ) {
std::string escaped;
// Reserve enough space for each character to be escaped
escaped.reserve(originalString.GetLength() * 2);
for (int iOriginal = 0; iOriginal < originalString.GetLength(); ++iOriginal) {
if (originalString[iOriginal] == charFind)
escaped += charInsert;
escaped += originalString[iOriginal];
}
return CString(escaped.c_str());
}
Upvotes: 11
Reputation: 2185
The mistakes have already been mentioned. But they strike me as the sort of problems anyone might have with quickly dashed-off code which has not been properly tested, particularly if they are not familiar with CString.
I'd worry more about the stylistic things, as they suggest someone who is not comfortable with C++. The use of the bool continueLoop is just plain poor C++. It represents a third of the function's code that could be eliminated by the use of a simple if...break construct, making the code easier to follow in the process.
Also, the variable name "originalString" is very misleading. Because they pass it by value, it's not the original string, it's a copy of it! Then they modify the string anyway, so it no longer is the same object or the same string of text as the original. This double lie suggests muddled thought patterns.
Upvotes: 5
Reputation: 140050
My gut reaction is: WTF. Initially by how the code is formatted (there are lots of things I don't like about the formatting) and then by examination of what the code is actually doing.
There's a serious issue with this developer's understanding of object copying in C++. The example is a WTF in itself (if the developer of the function really used his/her own function like this):
// Example call
strColHeader = insert_escape(strColHeader, ',', '\\'); //Get rid of the commas and make it an escape character
CString insert_escape ( CString originalString, char charFind, char charInsert )
strColHeader
as originalString
(notice that there's no &
)strColHeader
. The compiler will probably optimize this out to a single copy but still, passing around object copies like this doesn't work for C++. One should know about references.A more seasoned developer would have designed this function as:
void insert_escape(CString &originalString, char charFind, char charInsert)
or:
CString insert_escape(const CString &originalString, char charFind, char charInsert)
(And probably would have named the parameters a bit differently)
And as many have pointed out, the sane thing the developer could have done was to check the API documentation to see if CString
already had a Replace
method...
Upvotes: 3
Reputation: 5657
I always worry when I see a do .. while loop; IMO they're always harder to understand.
Upvotes: 0
Reputation: 545588
This is in Visual Studio C++ 6.0.
Gut reaction: blech. Seriously! The C++ compiler shipped with VC++ 6 is known to be buggy and generally performing very badly and it's 10 years old.
@Downvoters: consider it! I mean this in all seriousness. VC6 is just comparatively unproductive and should not be used any more! Especially since Microsoft discontinued its support for the software. There are cases where this can't be avoided but they are rare. In most cases, an upgrade of the code base saves money. VC++ 6 just doesn't allow to harness the potential of C++ which makes an objectively inferior tool.
Upvotes: 0
Reputation: 8805
If you're wanting an evaluation of this developer's C++ skill level, I'd say this demonstrates the lower end of intermediate.
The code gets the job done, and doesn't contain any obvious "howlers," but as others have written, there are better ways of doing this.
Upvotes: 2
Reputation: 12317
There is always a better implementation. If you are using the function as an example of the consultant not being very good you might also want to consider that while they did not know a function that already existed they might have experience and understanding of project construction.
Software development is not just about the perfect function but also how good the architecture of the whole thing is.
Upvotes: 0
Reputation: 4371
Looks like people have tackled some of the functionality aspects of this code for you, but I'd suggest staying away from variable naming like you've employed here.
With the exception of UI controls, it is generally frowned upon to use Hungarian notation. This is more important with numbers...for example:
I declare:
float fMyNumber = 0.00;
And then I use that in my entire application. But then, later, I change that to a double because I realize that I need more precision. Now I have:
double fMyNumber = 0.00;
It's true that most good refactoring tools could fix this for you, but it's probably best not to attach those prefixes. They are more common in some languages than others, but from a general style perspective, you should try to avoid them. Unless you're using Notepad, you probably have something akin to Intellisense, so you don't really need to look at the variable name to figure out what type it is.
Upvotes: 0
Reputation: 6846
CString has a Replace() method... (that was my 1st reaction)
I have seen a lot of bad code, and lots worse than this. However, not using built-in functionality when there's no apparent good reason not to is... poor.
Upvotes: 3
Reputation: 40309
Looks alright, if a bit, I dunno, hack. Better to use the library, but I wouldn't go and rewrite this routine.
Upvotes: 0
Reputation: 52679
hmm. I think
CString strColHeader;
strColHeader.Replace(",", "\\,")
would do just as well.
I don't like the code, I tend to break from the while loop instead of having an unnecessary bool 'continue' flag. That goes double when he could have used while (occurenceInd != 0)
as his loop control variable instead of the boolean.
Incrementing the counter also relies on "+2" which doesn't seem immediately understandable (not at a quick glance), and lastly (and most importantly) he doesn't seem to do comments.
Upvotes: 17