2

after years of writing Java, I would like to dig deeper into C++ again.

Although I think I can handle it, I don't know if I handle it the "state of the art"-way.

Currently I try to understand how to handle std::strings passed as const pointer to as parameter to a method.

In my understanding, any string manipulations I would like to perform on the content of the pointer (the actual string) are not possible because it is const.

I have a method that should convert the given string to lower case and I did quite a big mess (I believe) in order to make the given string editable. Have a look:

class Util
{
  public:
  static std::string toLower(const std::string& word)
  {
    // in order to make a modifiable string from the const parameter
    // copy into char array and then instantiate new sdt::string
    int length = word.length();
    char workingBuffer[length];
    word.copy(workingBuffer, length, 0);

    // create modifiable string
    std::string str(workingBuffer, length);

    std::cout << str << std::endl;

    // string to lower case (include <algorithm> for this!!!!)
    std::transform(str.begin(), str.end(), str.begin(), ::tolower);

    std::cout << str << std::endl;

    return str;
  }
};

Especially the first part, where I use the char buffer, to copy the given string into a modifiable string annoys me. Are there better ways to implement this?

Regards, Maik

9
  • please review the first chapters of your book ;) There is no const pointer to string in your code.... Commented Aug 3, 2018 at 9:05
  • 1
    If you have a class only with static member functions, a namespace is more appropriate... Commented Aug 3, 2018 at 9:13
  • @Aconcagua i like it when someone rephrases my sloppy comment using nicer words and i can delete mine :P Commented Aug 3, 2018 at 9:14
  • @Aconcagua Worth mentioning is that those namespace functions will be static by default. Commented Aug 3, 2018 at 9:42
  • @Ron I know what you mean, but your wording is just plain wrong: As functions now reside in a namespace, static changes its meaning and would restrict visibility to current compilation unit! Default visibility is "extern", though... Commented Aug 3, 2018 at 10:12

3 Answers 3

7

The parameter is const (its a reference not a pointer!) but that does not prevent you from copying it:

 // create modifiable string
std::string str = word;

That being said, why did you make the parameter a const reference in the first place? Using a const reference is good to avoid the parameter being copyied, but if you need the copy anyhow, then simply go with a copy:

std::string toLower(std::string word) { 
    std::transform(word.begin(), word.end(), word.begin(), ::tolower);
    // ....

Remeber that C++ is not Java and values are values not references, ie copies are real copies and modifiying word inside the function won't have any effect on the parameter that is passed to the function.

Sign up to request clarification or add additional context in comments.

3 Comments

As stated in my comment above, it is just for testing purposes that the parameter is const. I didn't realized that std::string str = word; would remove the constant attribute from the string. So in fact, that expression gives me a copy of 'word'? I tested it and of course, it works fine. Thank you!
@Kiamur it doesnt "remove the constant attribute from the string" sorry but I still hear the java philosophy in that sentence ;). In std::string str = word; the str is a (non const) string that is created from a copy of word. Its like you take a piece of chalk and copy your id number from your passport onto a blackboard. The id you wrote on the blackboard is not const, but the id in your passport still is
Just realized I've been writing const std::string & on autopilot, expecting Java to happen on C++.
2

you should replace all this:

// in order to make a modifiable string from the const parameter
// copy into char array and then instantiate new sdt::string
int length = word.length();
char workingBuffer[length];
word.copy(workingBuffer, length, 0);

// create modifiable string
std::string str(workingBuffer, length);

with simple this:

std::string str(word);

and it should work just fine =)

3 Comments

Yup, it works, and it is in fact what I was looking for. Any hint, where exactly I can find some kind of documentation that explains quite well, that with this construct the new str isn't const anymore? I hope you don't mind the question. I'm digging around by myself all the time, but maybe somebody of you has some great tutorials, where this is described very good. Thank you!
(I accept this as the answer for my question because it is the most direct one of all. As stated, All other input is very much appreciated!)
@Kiamur const std::string& word means you're passing not an actual string, but a constant reference, the compiler won't let you modify this parameter (unless you do some special casting tricks), thus saving you the memory by passing over a reference instead of the whole object. it's a common practice to pass parameters as const to make sure they won't be modified. and str is just a local copy of the parameter, that can be modified, since you need it to be.
0

As you must make a copy of the input string, you may as well take it by value (also better use a namespace than a class with static members):

namespace util {

    // modifies the input string (taken by reference), then returns a reference to 
    // the modified string
    inline std::string&convert_to_lower(std::string&str)
    {
        for(auto&c : str)
            c = std::tolower(static_cast<unsigned char>(c));
        return str;
    }

    // returns a modified version of the input string, taken by value such that
    // the passed string at the caller remains unaltered
    inline std::string to_lower(std::string str)
    {
        // str is a (deep) copy of the string provided by caller
        convert_to_lower(str);
        // return-value optimisation ensures that no deep copy is made upon return
        return str;
    }
}

std::string str = "Hello";
auto str1 = util::to_lower(str);
std::cout << str << ", " << str1 << std::endl;

leaves str un-modified: it prints

Hello, hello

See here for why I cast to unsigned char.

5 Comments

or simply: return convert_to_lower(str);... Not sure if I would have preferred void as return value for first function, even though (or perhpas because?) this prevents code like convert_to_lower(str).push_back(n);
considering that OP thought string& is a pointer you should imho explain what is the point of having those two overloads
@Aconcagua Does return convert_to_lower(str); really do the same? there should be no new string created.
@Walter [@+#$!], you are right!!! Assumed returning value and reference to would result in the same code, but that proved wrong even with std::string& ss = str; return ss; without intermediate function call (you never stop learning...). But wouldn't that even more be an argument for letting convert return void?
Thanks! This seems to go a little bit further than the question I asked and I appreciate it very much. The whole thing for me is to gain understanding and experience in different techniques on how to handle my "problem". For this solution here, I have still to think a little bit more, what it all means.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.