0

I'm new to c++, so please bear with me if this is a silly question.

The method below seems to create a string named reversePhrase but with no initial value and then use it phrase.evalPalindrome(reversePhrase):

void testForPalindrome(string origPhrase)
{
   string reversePhrase;
   bool isPalindrome;
   Palindrome phrase(origPhrase);


   if (phrase.evalPalindrome(reversePhrase))
   {
      cout << "This phrase IS a palindrome!" << endl; 
   }
   else
   {
      cout << "This phrase is NOT a palindrome." << endl; 
   }
   cout << "Original phrase: " << origPhrase << endl;
   cout << "Reverse phrase: " << reversePhrase << endl << endl;
}

In java this would create a null pointer exception. But I analyzed the method that is being called and it looks like it is accepts the address of a string.

bool Palindrome::evalPalindrome (string& reversePhrase)
{
   // code
}

But I don't understand how this is working. Does the initial string reversePhrase; simply assign memory to reversePhrase? If yes, how is the calling function able to then print out reversePhrase that is modified from another function (code is not shown, but it is modified from the other function).

It just seems like writing code this way is hard to read.

nullByteMe
  • 6,141
  • 13
  • 62
  • 99
  • `String reversePhase = new String();` in Java is equal to `string *reversePhase = new string();` in C++. In Java, `reversePhase` in this case is pointer, so you get an exception if you don't assign anything to it. – omerfarukdogan Feb 22 '15 at 15:06

5 Answers5

3

In java this would create a null pointer exception.

That's because Java is a different language with different object-creation syntax.

In C++, as soon as you wrote string reversePhrase, that object was fully-formed and ready to go.


But I analyzed the method that is being called and it looks like it is accepts the address of a string.

No, it accepts a reference to a string! And that's why the calling scope can later see the modified string!

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • In class we were told that `&` is the 'addressOf' operator. So I just assumed that's what was being passed. – nullByteMe Feb 22 '15 at 02:53
  • @inquisitor: [The symbol `&` means different things depending on where you see it! Consider, for example, binary AND.](http://stackoverflow.com/a/28368782/560648) – Lightness Races in Orbit Feb 22 '15 at 02:55
  • Point taken on the `&`! The reason this was confusing to me is because in java that code would never compile (i understand they are different languages). – nullByteMe Feb 22 '15 at 02:57
  • @inquisitor: Well yeah it wouldn't compile in FORTRAN either. Since you know they're different languages you also already know that you should stop thinking in Java terms when using C++! – Lightness Races in Orbit Feb 22 '15 at 02:59
  • Fair enough haha. Thanks for your insight here. It is much appreciated – nullByteMe Feb 22 '15 at 03:00
  • Hope this doesn't open a can of worms, but I thought java was pass by value? I don't entirely understand your last sentence. I ruminated over it for a few minutes before deciding to type this. In java if I pass a string object to a method I wouldn't be modifying the original string object in the calling method. – nullByteMe Feb 22 '15 at 03:08
2

string& reversePhrase doesn't declare evalPalindrome to take the address of a string. It declares the function to take a reference to a string. (Declaring it with string* would mean the address of a string, aka a pointer to a string.)

In C++, when you initialize a string with no arguments:

string reversePhrase;

it creates an empty string, so reversePhrase is equal to "". Thus it's not a null string, just an empty one, which you can safely pass by reference to the evalPalindrome function, which will then be able to modify the original string object passed to it.

Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • I see. So the `evalPalindrome(string& reversePhrase)` method is simply modifying the reference it is passed and that's why it can be used at the end of the calling method? – nullByteMe Feb 22 '15 at 02:48
  • @inquisitor Yes exactly, passing by non-const reference allows the function to modify the original object. – Emil Laine Feb 22 '15 at 02:51
  • So much is begining to make sense now. Would you agree that this makes the code harder to read? And is this must be why I see `const` used so much in c++ – nullByteMe Feb 22 '15 at 02:52
  • No, it specifically makes it easier to understand. Each way to pass objects to functions (either by value, (non-)const reference, or (non-)const pointer) conveys a distinct semantical meaning, [this answer here](http://stackoverflow.com/a/2139254/3425536) summarizes them really well. – Emil Laine Feb 22 '15 at 02:57
  • @inquisitor: Yes, and yes. – Lightness Races in Orbit Feb 22 '15 at 02:58
  • @zenith: It _is_ confusing that pass-by-reference is not at all indicated at the call site. I don't see how it "specifically makes it easier to understand" at all. – Lightness Races in Orbit Feb 22 '15 at 02:58
  • @LightnessRacesinOrbit Well yes certainly on the *call site* it does look a bit confusing. But not in the function declaration. I probably just misunderstood inquisitor's answer. – Emil Laine Feb 22 '15 at 03:01
1

You are not creating a pointer but a object of type string. It is never assigned so it should just be a blank string "". Getting the address to it will work fine as it is a valid object.

I am not sure how that function would be a working one though.

marsh
  • 2,592
  • 5
  • 29
  • 53
1

What is happening here is what is called pass by reference. Normally, when you pass a variable in C++, a copy of it is made. Which is why when you run the below, you will get "A", "B", "A".

int main(){
    string s = "A";
    cout << s << endl;
    cngLetter(s);
    cout << s << endl;
}

void cngLetter(string s){
    s = "B";
    cout << s << endl;
}

If you pass by reference, then it will update it on the main thread. The following will print "A", "B", "B"

int main(){
    string s = "A";
    cout << s << endl;
    cngLetter(s);
    cout << s << endl;
}

void cngLetter(string& s){
    s = "B";
    cout << s << endl;
}

Note that only one character was added to that, the & which causes a pass by reference, i.e. not a copy, but instead the memory address. No need for me to type up a lot in this post, as you can read up on it here

Now strings aren't unmanaged memory, so if you don't assign it at first, then you will instead get "", "B", "B"

int main(){
    string s;
    cout << s << endl;
    cngLetter(s);
    cout << s << endl;
}

void cngLetter(string s){
    s = "B";
    cout << s << endl;
}

Basically, a string that is not given an inital value is just an empty string.

David
  • 4,744
  • 5
  • 33
  • 64
-2

The '&' operator in this context is syntactical candy for '*'. Within the evalPalindrome method, while reversePhrase is passed in as a pointer, it is ALWAYS dereferenced. This makes the common error of not dereferencing a pointer impossible. You're right that it can make for confusing code, as the passed-in value can be modified similar to if it had been passed in as a pointer, except that the calling function has no indication that it is being passed in as a pointer unless you specifically look at the method signature.

  • `&` here is not an operator, and it is not "syntactical candy for '*'`, though I appreciate the comparison you're attempting to draw. Ultimately, though, you're fixating on the details of a potential _implementation_ and, in doing so, spreading some dangerous misinformation. – Lightness Races in Orbit Feb 22 '15 at 02:54
  • `&` objects take up no extra memory, unlike a `*` object which consists of (typically) 4 bytes. `&` is just another name for the object assigned to it. Kinda like I could call you Randy, or Kamrady, which both are you. – David Feb 22 '15 at 02:57
  • @David: Actually, it is unspecified whether a reference takes memory (`[C++11: 8.3.2/4]`), but that's an abstraction leak made necessary by the fact that a reference stored as a class data member is going to take up space. – Lightness Races in Orbit Feb 22 '15 at 03:00
  • In the case where a reference is used as a parameter, there's going to be space on the stack for it. – Randy Kamradt Sr. Feb 22 '15 at 03:06
  • @RandyKamradtSr.: No, not necessarily. Computers are not that simple. The function could be inlined and the entire reference optimised out. – Lightness Races in Orbit Feb 22 '15 at 03:10
  • I call it syntatical sugar only because the same exact code could be written with the address-of and dereferencing, the reference operator only makes it more succinct. When you can write code two different ways with the exact same outcome, the more succinct version is syntatical sugar. But by explaining it both ways, it may become easier to understand. I see no dangerous misinformation that I am spreading. – Randy Kamradt Sr. Feb 22 '15 at 03:33
  • That's not true whatsoever. – Lightness Races in Orbit Feb 22 '15 at 17:40