Passing C++ string Results

M

Mike Copeland

I have the following function, but it fails after the first
invocation whenever the length of the input variable is longer than the
previous data. Specifically:

strToUpper("5h"); // works
strToUpper("nope"); // fails (aborts)

Apparently the "static" keyword is the problem, but I don't know how
to assure that the function will always return the proper result from
all calls. Do I need the "static" at all with C++ strings or not? TIA

string strToUpper(string str)// force string data to UPPER case
{
size_t nnn;
static string strResult = str;
for(nnn = 0; nnn < str.length(); nnn++)
{
strResult.at(nnn) = toupper(strResult.at(nnn));
} // for
return strResult;
} // strToUpper
 
I

Ian Collins

Mike said:
I have the following function, but it fails after the first
invocation whenever the length of the input variable is longer than the
previous data. Specifically:

strToUpper("5h"); // works
strToUpper("nope"); // fails (aborts)

Apparently the "static" keyword is the problem, but I don't know how
to assure that the function will always return the proper result from
all calls. Do I need the "static" at all with C++ strings or not? TIA

The use of static in this example is both unnecessary and incorrect.

A static variable is initialised once, in this case to the first string
passed to the function. Since you are returning the result by value,
static is unnecessary.
string strToUpper(string str)// force string data to UPPER case
{
size_t nnn;
static string strResult = str;
for(nnn = 0; nnn < str.length(); nnn++)

This is also a bug, strResult.at(nnn) will throw an exception when nnn =
str.length(). Don't forget strings are zero indexed.
 
S

Stefan Ram

Apparently the "static" keyword is the problem, but I don't know how
to assure that the function will always return the proper result from
all calls. Do I need the "static" at all with C++ strings or not? TIA

What did make you believe in the first place that you had to
use »static«?
 
J

Jorgen Grahn

What did make you believe in the first place that you had to
use »static«?

I get the impression (from this posting and vague memories of his
earlier ones) that he's trying to learn C++ by trial and error.
If he is, it's not a strategy.

/Jorgen
 
G

Greg Martin

I have the following function, but it fails after the first
invocation whenever the length of the input variable is longer than the
previous data. Specifically:

strToUpper("5h"); // works
strToUpper("nope"); // fails (aborts)

Apparently the "static" keyword is the problem, but I don't know how
to assure that the function will always return the proper result from
all calls. Do I need the "static" at all with C++ strings or not? TIA

string strToUpper(string str)// force string data to UPPER case
{
size_t nnn;
static string strResult = str;
for(nnn = 0; nnn < str.length(); nnn++)
{
strResult.at(nnn) = toupper(strResult.at(nnn));
} // for
return strResult;
} // strToUpper

The static key insures your variable is initialized once and then
persists across invocations of your function. You are then iterating
over one string while using the length of another as a guard. You have
two statements that make no sense in this context - the static attribute
serves no purpose in this context and str.length is just wrong, though
it will work correctly if you remove the static from your assignment.
You are iterating over strResult so use its length as your guard and you
don't want the first invocation to persist strResult so remove static.
 
I

Ike Naar

This is also a bug, strResult.at(nnn) will throw an exception when nnn =
str.length(). Don't forget strings are zero indexed.

Is it? Here's the complete fragment:

size_t nnn;
static string strResult = str;
for(nnn = 0; nnn < str.length(); nnn++)
{
strResult.at(nnn) = toupper(strResult.at(nnn));
} // for

strResult.at(nnn) is never called with nnn = str.length(),
the loop body is only executed for nnn < str.length().
 
I

Ike Naar

Is it? Here's the complete fragment:

size_t nnn;
static string strResult = str;
for(nnn = 0; nnn < str.length(); nnn++)
{
strResult.at(nnn) = toupper(strResult.at(nnn));
} // for

strResult.at(nnn) is never called with nnn = str.length(),
the loop body is only executed for nnn < str.length().

Sorry, missed the fact that strResult is static, and therefor
only initialized when the function is called for the first time,
strResult.at(nnn) can indeed throw an exception.
 
G

goran.pusic

The use of static in this example is both unnecessary and incorrect.



A static variable is initialised once, in this case to the first string

passed to the function. Since you are returning the result by value,

static is unnecessary.








This is also a bug, strResult.at(nnn) will throw an exception when nnn =

str.length(). Don't forget strings are zero indexed.

That's not his bug.
nnn will not reach str.length due to "nnn < str.length()".

The bug is related the use of static: strResult is created with value "5th"
on the first call. On the second, strResult is still "5th".
nnn will eventually become 3. When that happens, strResult.at
will throw out_of_range.

Mike, just remove static. That will cause strResult to be a copy of str
on every entry to the function.

That said, you'll be better off by removing strResult altogether:

string strToUpper(string str)// force string data to UPPER case
{
size_t nnn;
for(nnn = 0; nnn < str.length(); nnn++)
{
str.at(nnn) = toupper(str.at(nnn));
} // for
return str;
} // strToUpper

And if this is a rewrite of a C function "char* strToUpper(char* str)", where str was modified in-place and returned back, you should better do:

void strToUpper(string& str)// force string data to UPPER case
{
size_t nnn;
for(nnn = 0; nnn < str.length(); nnn++)
{
str.at(nnn) = toupper(str.at(nnn));
} // for
} // strToUpper

(The original C function was rather wrong to "return" anything, too; conceptually, it works with the string in-place, and the caller already has a pointer to that string; there's no great benefit in "returning" it back)

Goran.
 
J

Jorgen Grahn

.
I get the impression (from this posting and vague memories of his
earlier ones) that he's trying to learn C++ by trial and error.
If he is, it's not a strategy.

(I meant to write "not a good strategy". Although some might find the
above more fitting.)

/Jorgen
 
T

Tobias Müller

(The original C function was rather wrong to "return" anything, too;
conceptually, it works with the string in-place, and the caller already
has a pointer to that string; there's no great benefit in "returning" it back)

It is often convenient to write:
f(strToUpper(s));
instead of:
strToUpper(s);
f(s);

operator= that returns *this belongs to the same category.

Tobi
 
N

none

Does the caller really always already has a modifiable pointer to the
string? This is a serious restriction on callers.

IMO, there is no great benefit in executing in-place. Really, the
only potential benefit is one of optimisation but I would hope that
most of the time, the cost is allocating and copying a generally small
string is not important.
It is often convenient to write:
f(strToUpper(s));
instead of:
strToUpper(s);
f(s);

operator= that returns *this belongs to the same category.

I strongly second that.

What Goran suggests is a minor optimization (save allocating a new
string) but makes the code more complex, less flexible and more bug
prone. It makes writing const-correct code much more difficult.

There are many examples where a strToUpperInPlace makes things more
difficult:

strToUpper("Hard Coded String") is possible while with an InPlace-style
function, it isn't

some_type foo(std::string const & s)
{
// ...
std::string sLowered strToUpper(s);
// posible with with strToUpperInPlace(), it would force making
// a copy prior to calling the function
// ..
}

std::string strToUpper(std::string cosnt & s) can be used to sort or
compare in a case-insensitive way while a strToUpperInplace can't (it
would squash the data rather than allow case-insensitive compare)

std::string sFiltered = strUnquote(strToUpper(rawString))

etc.

Yannick
 
G

goran.pusic

Does the caller really always already has a modifiable pointer to the

string? This is a serious restriction on callers.



IMO, there is no great benefit in executing in-place. Really, the

only potential benefit is one of optimisation but I would hope that

most of the time, the cost is allocating and copying a generally small

string is not important.






I strongly second that.



What Goran suggests is a minor optimization (save allocating a new

string) but makes the code more complex, less flexible and more bug

prone. It makes writing const-correct code much more difficult.

Well, now... My first suggestion was to merely remove the static.

My second version of the function was written in a (presumed) context of an
existing one that works with a char* (not a const char*), as it is +/- usual
to do so in C).

While one could argue the speed advantage of avoiding a copy, I didn't.

Code in the function is actually shorter than anything else,
so the complexity is on the caller side.
But there, the only complexity is e.g. going from

f(strToUpper(s))

to

strToUpper(s);
foo(s);

**If** modification is made in-place, I personally would prefer making a side effect explicit by exactly preventing function call chaining.

As for const-correctness: it's merely a case of explicitly making a copy ifneeded. Not exactly a deal-breaker. ;-)

Goran.
 
N

none

Well, now... My first suggestion was to merely remove the static.

Agree with this. "static" is a bug.
My second version of the function was written in a (presumed) context of an
existing one that works with a char* (not a const char*), as it is +/- usual
to do so in C).

But this is a rather strong limitation on client and my point is that
it leads leads poorer caller-side code.

C++ group so we should use C++ idioms rather than C but note that even
libc toupper return the value rather than modify its input.
While one could argue the speed advantage of avoiding a copy, I didn't.

You state that there are "no great benefits" to returning a string.
My statement is that there are even less great benefits to modifying in
place apart from a possible speed advantage. What other advantages do
you see to the in-place style?

I listed several benefits of returning it instead of modifying in
place. I'll agree that none of then are "great" "trumping arguments"
that justify 100% of returning vs 0% of in-place but I certainly
believe that these advantages are sufficient unless you have good
reason to believe that the possible speed advantage will be needed
(probably should be able to measure it).
Code in the function is actually shorter than anything else,
so the complexity is on the caller side.

Generally, it is better to place complexity in the callee side than in
the caller side. Reason: code reuse. The callee function should be
written once and called multiple times so you pay the complexity only
once. If you impose complexity to the caller, you have to pay it
every times the function is called.
But there, the only complexity is e.g. going from

f(strToUpper(s))

to

strToUpper(s);
foo(s);

**If** modification is made in-place, I personally would prefer making a
side effect explicit by exactly preventing function call chaining.

Of course the chaining style strUnquote(strToUpper(s)) is meant to
return by value and does not modify its argument. You'd just end up
modifying a temporary which is incorrect.

I agree with you that it is always desireable to make incorrect
constructs impossible (e.g. won't compile)
But how do you intend to *prevent* function chaining?
You may yourself only write in-place style functions but you will not
work with what are very common C++ idioms:

void strToUpperInPlace( std::string & s);

There is nothing in the above signature that prevent function chaining:

std::string s = "BlahBlahBlah";
strToUpperInPlace(s); // works as intended
strToUpperInPlace(s.substr(0,5)); // Ooops compile but doesn't work

std::vector<std::string> vs;
// populate vector
strToUpperInPlace(vs[2]); // Oops compile but doesn't work.

Taking a pointer input void strToUpperInPlace( std::string * s)
makes it a bit more awkward to chain so would discourage function
chaining but not prevent it either.
As for const-correctness: it's merely a case of explicitly making a copy
if needed. Not exactly a deal-breaker. ;-)

Agree, none of the benefits are 100% deal breakers. But they are
small benefits that together lead to better code.

In my experience, with using the "in place" style, the programmers
will tend to end up creating a system where all the data are passed
are by non-const references and/or non-const pointers and when trying
to read/review/maintain such code base, you can never know if a
function argument is going to be modified or not sometimes deep down
the calling chain.

Code may even tend to pessimise itself cause you can never trust that
data you pass as input to a function will not be trampled somewhere
down the line so you may end up making a temporary copy "just in case"
for safety.

Yannick
 
G

goran.pusic

Agree with this. "static" is a bug.








But this is a rather strong limitation on client and my point is that

it leads leads poorer caller-side code.



C++ group so we should use C++ idioms rather than C but note that even

libc toupper return the value rather than modify its input.






You state that there are "no great benefits" to returning a string.

My statement is that there are even less great benefits to modifying in

place apart from a possible speed advantage. What other advantages do

you see to the in-place style?

Code does what the (presumed) C version did that.

I agree with you, and we're both nitpicking.
I listed several benefits of returning it instead of modifying in

place. I'll agree that none of then are "great" "trumping arguments"

that justify 100% of returning vs 0% of in-place but I certainly

believe that these advantages are sufficient unless you have good

reason to believe that the possible speed advantage will be needed

(probably should be able to measure it).







Generally, it is better to place complexity in the callee side than in

the caller side. Reason: code reuse. The callee function should be

written once and called multiple times so you pay the complexity only

once. If you impose complexity to the caller, you have to pay it

every times the function is called.







Of course the chaining style strUnquote(strToUpper(s)) is meant to

return by value and does not modify its argument. You'd just end up

modifying a temporary which is incorrect.



I agree with you that it is always desireable to make incorrect

constructs impossible (e.g. won't compile)

But how do you intend to *prevent* function chaining?

Easy: by not returning a value ;-)
You may yourself only write in-place style functions but you will not

work with what are very common C++ idioms:



void strToUpperInPlace( std::string & s);



There is nothing in the above signature that prevent function chaining:



std::string s = "BlahBlahBlah";

strToUpperInPlace(s); // works as intended

strToUpperInPlace(s.substr(0,5)); // Ooops compile but doesn't work

Bad example. First off, it should not compile (will on MSVC with extension turned ON). Second, what do you even expect this to do? that [0, 5) of s goes upper? That's a serious leap of faith.
std::vector<std::string> vs;

// populate vector

strToUpperInPlace(vs[2]); // Oops compile but doesn't work.

Erm... that should work, because vector does

reference operator[] (size_type n);
Taking a pointer input void strToUpperInPlace( std::string * s)

makes it a bit more awkward to chain so would discourage function

chaining but not prevent it either.

Ugh. Grautious use of pointers - stylys horribilis. To me, when I see a pointer parameter in C++, I think "pointer is there because parameter can be null". (And the world of C++ code would be a better place if people would obey that). And in this case, it makes no sense whatsoever - if the pointyer is null, there's certainly nothing to "up" anyhow, and the code is already borked elsewhere ;-).
Agree, none of the benefits are 100% deal breakers. But they are

small benefits that together lead to better code.



In my experience, with using the "in place" style, the programmers

will tend to end up creating a system where all the data are passed

are by non-const references and/or non-const pointers and when trying

to read/review/maintain such code base, you can never know if a

function argument is going to be modified or not sometimes deep down

the calling chain.

Agreed.

But the onus really should be on correct design - if a parameter it's meantto be an "input", it's const, end of story. Your imaginary developers are actively trading some typing for incorrect design. Tsk, tsk ;-).

Goran.
 
S

Seungbeom Kim

IMO, there is no great benefit in executing in-place. Really, the
only potential benefit is one of optimisation but I would hope that
most of the time, the cost is allocating and copying a generally small
string is not important.
[...]

There are many examples where a strToUpperInPlace makes things more
difficult:

Moreover, there are trickier cases. For example, in German, "ß" exists
only in lowercase and is capitalized as "SS", so capitalization can
increase the string length. If you don't have slack some space after
the end (i.e. capacity() > size()), in-place modification is not just
possible. And even when it is, all characters following "ß" should be
copied to make room for "SS". It may be simpler just to store the result
in a new string and return it. :)
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,165
Latest member
JavierBrak
Top