views:

462

answers:

7
class mystring {
 friend ostream& operator<<(ostream &out, const mystring ss) {
        out << ss.s;
        return out;
    }
private:
    string s;
public:
    mystring(const char ss[]) {
        cout << "constructing mystring : " << ss << endl;
        s = ss;
    }
};

void outputStringByRef(const mystring &ss) {
 cout << "outputString(const string& ) " << ss << endl;
}

void outputStringByVal(const mystring ss) {
 cout << "outputString(const string ) " << ss << endl;
}

int main(void) {
    outputStringByRef("string by reference");
    outputStringByVal("string by value");
    outputStringByRef(mystring("string by reference explict call mystring consructor"));
    outputStringByVal(mystring("string by value explict call mystring constructor"));
} ///:~

Considering the above example,we could not modify the pass-by-reference variable,neither could we modify the pass-by-value variable.The output of each methods is same.Since there is no difference between these two method,why do C++ support both methods?

thanks.

+2  A: 

With outputStringByRef you must ensure that the variable you're passing a reference to remains alive and unchanged for as long as outputStringByRef needs it. with outputStringByVal the variable you passed can die or get out of scope and the copy that the function has is still ok.

shoosh
+6  A: 

f(const string&) takes string by const reference: fis operating directly on the string object passed by reference: there is no copy involved. const prevents modifications to the original object though.

f(const string) takes a string value, which means f is given a copy of the original string. Even if you drop const, when passing by value, any modification to the string is lost when f returns.

I don't know exactly what you mean by "why do C++ support both methods?". It's just general overloading rules that apply.

Gregory Pakosz
`why do c++ support both methods`,because at first,i didn't see the difference between this two functions.i thought the two are the same.after digging into the assembly g++ and msvc generated,it seems much the same way by passing the same address of the constant.
Jichao
+2  A: 

your object could contain a mutable member, which can be modified even with a const reference

josefx
+4  A: 

f(string s) pass by value the string s, in other words it creates a copy and initializes it with the value of the string you pass. Any change to the copy, will not be propagated to the original string you passed to call the function. In f(const string s) const is redundant because you can't anyway change the original value.

In f(const string& s) instead the string is not copied but you pass a reference to it. This is usually done when you have a large object so the "pass-by-value" can produce an overhead ( that's why c++ supports both methods ). Passing by reference means that you can change the value of the "large" object you pass, but because of the const specifier, you can't modify it. It's a sort of "protection".

Salv0
`const string s` may be needed if it better conveys the intent
Phil Nash
What is the difference in intent between `string s` and `const string s`?
Martin B
Martin B: it's an internal detail for the function and might help whomever has to write that function, but the signatures are compatible (you can do `void f(int const); typedef void (*FP)(int); FP p = `) and it has no significance to callers.
Roger Pate
A: 

There is (almost) no difference in terms of being able to modify the string within the function. However there is a big difference in terms of what is being passed. The const mystring &ss overload takes a const reference to the string. Although it cannot modify it, it is the same memory being addressed. If the string is long this can be a big factor (assuming the string is not implemented using copy-on-write). The const mystring ss form is making a copy of the string, so different memory will be addressed.

Actually the const mystring &ss form could change the string, if a const_cast<mystring&> was used - although I wouldn't recommend that here.

Phil Nash
+1  A: 

Imagine you want to print an object that can't be copied:

Thread th;
// ...
cout << th; // print out informations...

The reference version will not copy the thread, but will take the address of th and create an alias to it. The other version would try to copy the thread when passing by value - but copying may not be senseful for such an object (would there be one additional thread then?).

It may help you to think of copy an object as cloning an object. Copying th above in C++ does not merely mean to have another handle to the same object as in Java - it does mean to implicitly clone the object denoted, and have a whole copy of it. So the question is similar to "Why does Java support both Object.clone and copying of references?" - both have different purposes.

And then there is a matter of performance too, after all. You don't want to copy each and every time you pass something around for resource hungry objects.

Johannes Schaub - litb
+2  A: 

There is a difference between the two. Consider the following:

#include <iostream>
#include <string>
using std::string;

string g_value;

void callback() {
    g_value = "blue";
}

void ProcessStringByRef(const string &s) {
    callback();
    std::cout << s << "\n";
}

void ProcessStringByValue(const string s) {
    callback();
    std::cout << s << "\n";
}

int main() {
    g_value = "red";
    ProcessStringByValue(g_value);
    g_value = "red";
    ProcessStringByRef(g_value);
}

Output:

red
blue

Just because a reference is const inside a function, doesn't mean that the referand can't be modified via other references (the situation of one object having multiple references or pointers to it is called "aliasing"). Thus there is a different between passing a const reference, and passing a const value - in the case of the reference, the object might change after the call is made. In the case of the value, the callee has a private copy, which will not change.

Since they do different things, C++ lets you choose which you want.

There are consequences for performance either way - when you pass by value, a copy has to be made, which costs. But the compiler then knows that only your function can possibly have any references to that copy, which might allow other optimisations. ProcessStringByRef cannot load the contents of the string for printing until callback() has returned. ProcessStringByValue can, if the compiler thinks doing so is faster.

Usually you care about the copy, not the order of execution of instructions, because usually the copy is way more expensive. So usually, you pass by reference where possible for objects that are non-trivial to copy. But the possibility of aliasing sometimes has really serious consequences for performance, by preventing certain optimisations. That's why "strict aliasing rules" exist, and the restrict keyword in C99.

Steve Jessop