A Better Way?

M

Mike Copeland

Is there a better way (less code, less convoluted, etc.) to access
the last character of a string variable than this?:

if(str2.at(str2.length()-1) != '/') str2 +="/";
 
V

Victor Bazarov

Is there a better way (less code, less convoluted, etc.) to access
the last character of a string variable than this?:

if(str2.at(str2.length()-1) != '/') str2 +="/";

Try 'back' member function:

if (str2.back() != '/') str2 += '/';

And, RTFM.

V
 
B

Balog Pal

Is there a better way (less code, less convoluted, etc.) to access
the last character of a string variable than this?:

if(str2.at(str2.length()-1) != '/') str2 +="/";

I have a function with equivalent of that called MakeEndWith.
 
B

Balog Pal

If it's not empty, what would .at(-1) do?

Nothing we'd like. So an extra score to make it a function that does the
thing right, and brings the info in its name. Instead of pasting around
expressions that may be bad part of the time and in any case take more
toll on reading.
 
Ö

Öö Tiib

Nothing we'd like. So an extra score to make it a function that does the
thing right, and brings the info in its name. Instead of pasting around
expressions that may be bad part of the time and in any case take more
toll on reading.

Was it for file paths? Use a library that deals with file paths (like
boost::filesystem). Was it for URIs? Some network/uri was even proposed
into std I think. If there is need to morph some dirty user-entered
string into path (or URI) then use std regex stuff.

On any case suppress that urge to invent a square wheel again. ;)
 
R

Rui Maciel

Mike said:
Is there a better way (less code, less convoluted, etc.) to access
the last character of a string variable than this?:

if(str2.at(str2.length()-1) != '/') str2 +="/";

It may not be as concise, but here's a suggestion:

<code>
#include <string>
#include <iostream>

void foo(std::string &text, std::string::value_type const c)
{
if( text.empty() || *(--text.end()) != c)
{
text += c;
}
}


int main(void)
{
using namespace std;

string text = "this is a string";

cout << "string: \"" << text << "\"" << endl;

foo(text, '/');

cout << "string: \"" << text << "\"" << endl;

return 0;
}
</code>


Rui Maciel
 
V

Victor Bazarov

Adding a bug doesn't justify adding other bugs.

Huh? With partial code posted the replacement code correctness is only
required to be as that of the original code. With the original code the
assumption is that the string is not empty. Based on the same
assumption the new code is proposed. Assuming that the original code
does NOT have a bug is no worse than assuming that the original code
DOES have a bug. So, there.

V
 
L

Luca Risolia

If it's not empty, what would .at(-1) do?

When the string is empty, .at(-1) throws std::eek:ut_of_range, while
..back() is undefined behaviour (which results in a crash if you are lucky).
 
Ö

Öö Tiib

Huh? With partial code posted the replacement code correctness is only
required to be as that of the original code. With the original code the
assumption is that the string is not empty.

basic_string<3>::at(-1) throws out_of_range that is well-defined behavior.
I usually avoid catching it without rethrowing so it crashes. So for
me it does not matter and original code was defective.

basic_string<3>::back() on empty string is guaranteed to *not* throw.
Otherwise it is undefined behavior. In most modern implementations
it seems to crash too.

It is about different shades of dark of pots and kettles.
 
L

Luca Risolia

Is there a better way (less code, less convoluted, etc.) to access
the last character of a string variable than this?:

if(str2.at(str2.length()-1) != '/') str2 +="/";

str2 = std::regex_replace(str2, std::regex("[^/]$|^$"), "$&/");

If str2 is originally empty, then it will result in "/".
 
L

Luca Risolia

basic_string<3>::at(-1) throws out_of_range that is well-defined behavior.
I usually avoid catching it without rethrowing so it crashes. So for
me it does not matter and original code was defective.

basic_string<3>::back() on empty string is guaranteed to *not* throw.
Otherwise it is undefined behavior. In most modern implementations
it seems to crash too.

It is about different shades of dark of pots and kettles.

Not handling an exception is not undefined behaviour though.
 
R

Rui Maciel

Victor said:
Huh? With partial code posted the replacement code correctness is only
required to be as that of the original code. With the original code the
assumption is that the string is not empty. Based on the same
assumption the new code is proposed. Assuming that the original code
does NOT have a bug is no worse than assuming that the original code
DOES have a bug. So, there.

Commendable effort.


Rui Maciel
 
L

Luca Risolia

Luca Risolia said:
Is there a better way (less code, less convoluted, etc.) to access
the last character of a string variable than this?:

if(str2.at(str2.length()-1) != '/') str2 +="/";

str2 = std::regex_replace(str2, std::regex("[^/]$|^$"), "$&/");

Is this an attempt to come up with the most convoluted and least
efficient solution to the problem as you can?

It's a great benefit to get familiar with regular expressions (which are
not specific to C++ only) and profit by std::regex to solve those kind
of problems with strings, starting from simple cases like the above. By
looking at the code given by the OP and considering what "/" separators
could be for, I don't think efficiency is the main concern there, nor
the OP talked about efficiency explicitly.
 
N

Nobody

if(str2.at(str2.length()-1) != '/') str2 +="/";

str2 = std::regex_replace(str2, std::regex("[^/]$|^$"), "$&/");

Is this an attempt to come up with the most convoluted and least
efficient solution to the problem as you can?

It's a great benefit to get familiar with regular expressions (which are
not specific to C++ only) and profit by std::regex to solve those kind
of problems with strings, starting from simple cases like the above. By
looking at the code given by the OP and considering what "/" separators
could be for, I don't think efficiency is the main concern there, nor
the OP talked about efficiency explicitly.

But if you're going to learn to use regexps, you should at least learn to
use them correctly. In particular, you shouldn't construct multiple
temporary regexp objects from a given string literal, as constructing a
regexp can be expensive.

std::regex objects should normally be "static const". If you need to use
the imbue() method, you should arrange for this to be done only once, as
it will require the regexp to be recompiled.
 

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,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top