Search code examples
c++constantspass-by-referencepass-by-value

Any differences between f(const string &) and f(const string )?


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.


Solution

  • 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 even though no aliasing actually occurs. That's why "strict aliasing rules" exist, and the restrict keyword in C99.