3

The following output is not clear to me. Why in the first case output is: Joni Gallo, while in the second case (after I changed only one line), output is: Jonlo

Output of this:

// classes and default constructors #include <iostream> #include <string> using namespace std; class Example3 { string data; public: Example3 (const string& str) { data = str; // data.erase(3,5); } Example3() {} void doit() { data.erase(3,5); } const string& content() const {return data;} }; int main () { Example3 foo("Joni Gallo"); Example3 bar (foo); bar.doit(); cout << "content: " << foo.content() << '\n'; return 0; } 

is Joni Gallo, while output of this:

// classes and default constructors #include <iostream> #include <string> using namespace std; class Example3 { string data; public: Example3 (const string& str) { data = str; data.erase(3,5); } Example3() {} void doit() { // data.erase(3,5); } const string& content() const {return data;} }; int main () { Example3 foo("Joni Gallo"); Example3 bar (foo); bar.doit(); cout << "content: " << foo.content() << '\n'; return 0; } 

is: Jonlo

? Why? Why erase affected the original object in the second case, but not in first?

PS Also what does passing const string& str in constructor and then assigning it to member variable mean - does it mean everytime I change the member variabe content the original objects contents (whose reference was passed to the constructor) will also be changed? (like it would be with pointers)

10
  • Well you erase'd in the original object's string in its constructor, so of course it modified it. Commented Aug 29, 2015 at 17:42
  • They are two different instances. In the first sample you change data in bar while you print foo::data that's unchanged. In the second case in fooconstructor you change data. Commented Aug 29, 2015 at 17:43
  • @Jepessen: In the first case erase is called in constructor in the second case in function - that is the only difference. Why in first case original object is not changed and in the second case it is changed? Commented Aug 29, 2015 at 17:44
  • 1
    In your second snippet foo erases its own string in its constructor. Commented Aug 29, 2015 at 17:49
  • 1
    If you used a debugger, you could easily see what is happening. Debuggers allow you to execute one statement at a time see values of variables. Commented Aug 29, 2015 at 17:50

4 Answers 4

4

First note that even though you pass the string by reference for construction, you declared it without reference as a member of the class. So every class instance will have its own string. When you assign a reference to a non-reference variable, a copy is made. If you then change the non-reference copy (here your data member variable) the reference is not changed.

In the first program you edit the data member in the doit member function. In the second one you do it in the constructor.

First program:

  • foo is constructed with "Joni Gallo" set as data.
  • bar is constructed with foo. So it also has "Joni Gallo" as data.
  • Now you can do whatever you want with bar. It will not change the data of foo.
  • So the result is still "Joni Gallo"

Second program:

  • foo is constructed with "Joni Gallo" and the erase operation removes from position 3 with length 5. So the data member of foo is "Jonlo".
  • Again, nothing what happens to bar will change foo's data member.
  • So the result is "Jonlo".

In conclusion the result you observe has nothing to do with foo's member being modified because of a reference. You probably missed that the construction would affect both foo and bar.

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

1 Comment

@userq No, if you assign a reference to a non reference variable, a complete copy is made. It only works the other way around.
2

In your first sample you change bar instance, so foo remain unchanged and the content is what you've put in constructor.

In the second case inside Example3 constructor you perform some change that's reflected in foo. They are different object so modification to one does noe affect the other one.

1 Comment

bar does not do anything to foo. In your first sample foo constructor stores the string as is, and then print it. It does not care what bar does in the meanwhile. In your second sample again, it's foo itself that changes the string inside its constructor, and again bar has nothing to do with it.
2

The difference is in the timing of data.erase: in the second case it is done in the constructor of foo, and then the modified string is copied to bar by the copy constructor. Even if you comment out the declaration of bar and the call to doIt (which is no-op anyway) the same modified string would get printed.

In the first case, however, no erasure is done on foo's data at all, so the original string gets printed. Again, the declaration of bar and the call to doIt can get commented, because foo's data is disconnected from that of bar.

Comments

1

Global

string data; 

Is a string. Not a reference to a string or a pointer to a string. Any strings assigned to data will be copied.

data = string: Copy.

data = string reference: copy.

data = string pointer: compiler error.

data = char array: copy.

data = char pointer: copy.

Assuming the char array and char pointer are properly terminated. If not, undefined behaviour.

Source 1:

Example3 foo("Joni Gallo"); 

Makes foo. foo copies supplied string foo.data = "Joni Gallo".

Example3 bar (foo); 

Makes bar. Bar copies foo, so it gets a copy of foo's copy of the source string. bar.data = "Joni Gallo".

bar.doit(); 

Erases part of bar's copy of the string. bar.data = "Jonlo".

cout << "bar's content: " << foo.content() << '\n'; 

Is a lie. This prints out foo's copy of the string.

Source 2:

Example3 foo("Joni Gallo"); 

Makes foo. foo copies supplied string and erases part of the copy. foo.data = "Jonlo".

Example3 bar (foo); 

Makes bar. Bar copies foo, so it gets a copy of foo's edited copy of the source string. bar.data = "Jonlo".

bar.doit(); 

Does nothing. bar.data = "Jonlo".

cout << "bar's content: " << foo.content() << '\n'; 

Is still a lie, but this time foo's copy and Bar's copy will be identical.

Comments