I have been following this tutorial and I can't understand this section.
So it says that pass by value creates copy of the data so that can be ineffiecient, since it creates copy of the data, makes sense:
string concatenate (string a, string b)
{
return a+b;
}
then you have this, to 'solve the creating copies of data' issue:
string concatenate (string& a, string& b)
{
return a+b;
}
which makes sense since it is using references.
But I do not get this:
string concatenate (const string& a, const string& b)
{
return a+b;
}
Which says:
By qualifying them as const, the function is forbidden to modify the values of neither a nor b, but can actually access their values as references (aliases of the arguments), without having to make actual copies of the strings.
Why just not use the second way? In this example no modification of data is being done anyway? Can somebody give me a better example ?
Is it just done for safety reasons?
If the strings you actually have are const, or you only have const references to them, then you can pass them to this function:
string concatenate (const string& a, const string& b);
But you cannot pass them to this function:
string concatenate (string& a, string& b);
If your strings aren't const, then you can pass them to either function anyway. So other than ensuring that you don't modify the strings unintentionally, the const on the parameter allows for a more versatile function, which can accept either const or non-const arguments.
For example:
string concatenate_non_const (string& a, string& b)
{
return a+b;
}
string concatenate_const (const string& a, const string& b)
{
return a+b;
}
int main()
{
std::string s1 = "hello";
std::string s2 = "world";
const std::string cs1 = "hello";
const std::string cs2 = "world";
concatenate_const(s1, s2); // okay
concatenate_const(cs1, cs2); // okay
concatenate_non_const(s1, s2); // okay
concatenate_non_const(cs1, cs2); // error
}
Also, besides objects which are declared const, there is also temporaries to think about, which cannot be bound to non-const references.
concatenate_const("hello", "world"); // okay
concatenate_non_const("hello", "world"); // error
Why just not use the second way ? In this example no modification of data is being done anyway? Can somebody give me a better example ?
In your case here, where you are writing the function, It really doesn't matter, since you yourself aren't changing the parameters.
A better Example
A better example for using references over const references is for example with a swap function. Take this for example, which swaps 2 ints.
void swap(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
Now, in the example above, you cannot use a const reference, since the assignment to a and b would qualify as modification. In a function like above, references are very useful, and the const alternative would not work.
A less Concrete Example
Here is a less concrete example, that illustrates the same concepts as the swap(a,b) function:
void pre_incr(int& a)
{
++a;
}
Now the reason why this function is less concrete than the swap() one is that, you could have equally used pass by value like this:
void pre_incr(int a)
{
return ++a;
}
Either way though, both functions illustrate the difference between pass by const reference and pass by normal reference, and also pass by value.
Is it just done for safety reasons ?
Much of what constitutes a programming language are "safety reasons", otherwise we could be jumping around labels in assembly like code.
Making the parameters of your function references to const strings serves two purposes:
You cannot accidentally modify the referenced strings.
It clearly documents "the strings you pass here will not be modified" to both other programmes (or your future self) and the compiler (and optimizer).
Consider this scenario:
string a = "foo", b = "bar";
cout << concatenate(a, b); // "foobar"
You get what you expect, even if you'd modified the passed strings in your concatenation function.
string a = "foo", b = "bar";
cout << concatenate(a, b);
// some code
string c = "baz";
cout << concatenate(a, c); // "Aaaabaz"
You'd probably search all of that "some code" to find modifications to a before even considering to look into concatenate ...
Also note that the first example (single use of the parameter strings) is what you'd likely find in a unit test for concatenate.
When you pass a string in the first method with no const and no & it needs to be copied into the function which is inefficient. When you pass a reference it is not copied. When you pass by const reference it avoids the inefficiency of copying while not allowing the function to modify the string.
Related
I want to know is it mandatory to have constant arguments in the functions.
Recently I had in interview and wrote a code like below
int numofsubstring(string s1, string s2)
{
int nCount =0;
size_t pos;
while((pos = s1.find(s2)) != string::npos)
{
nCount++;
s1 = s1.substr(s1.find(s2)+s2.length());
}
return nCount;
} //number of times s2 is present in s1
The panel was expecting const string&s1 ,const string&s2 but i didn't wrote bcz of substr functionality usage...
can any one guide what's the standardised format to write the code....
the panel was insisting to improve the arguments in the function.
To the extent that there is "a rule" the rule would be
if you have some function that takes a T and you can pass a const T& instead without affecting correctness then you should pass a const T&.
It's about eliminating unnecessary copies. Passing a references is like passing a pointer. Nothing gets copied so the performance of the function will be better.
No it is not mandatory to have constant arguments in the functions. Note that the function you wrote is using pass by value. While if you had function parameters as const std::string& then it is pass by reference.
One of the reason for using const std::string& version is that in this case there will be no "copying" of passed strings, so it is faster(for very long strings) than the pass by value version.
Also in the case of pass by value the arguments passed will be copied and each of the argument will be destroyed after the function scope ends. This destruction part will not happen in the pass by reference version.
Edit:
If you want that the arguments passed to the functions should not be changed inside the function body then you can add const. Below is the way to make the arguments const that is they cannot be changed inside the function body anymore.
WAY 1
//pass by value, now that we have added const the arguments s1 and s2 cannot be changed inside the function body
int numofsubstring(const string s1, const string s2)
{
//some code here
}
WAY 2
//pass by reference, now that we have added const the arguments s1 and s2 cannot be changed inside the function body
int numofsubstring(const string& s1, const string& s2)
{
//some code here
}
I read it from 'Data Structures and Algorithm Analysis in C++'. The return type of the member function operator= is const Vector&. I wonder if the vector can be modified later?
C++ Primer says we can not change a const reference, it gives this example:
const string& shorterString(const string& s1 , const string& s2)
shorterString("hi","bye") = "X" //wrong
Usually operator= returns a non-const reference to the caller. You can see this in classes from STL, for example.
However, the return type rarely matters, because to return something from assignment is an additional effect which, for example, allows chaining:
a = (b = (c = d));
(a = b).callMethod();
operator= could be void as well, and assignment expressions couldn't be used somewhere else. But they would still work, modify its argument and leave it modifiable, i.e. non-const:
A a, b, c;
b = c; //call, say, void A::operator=(const A &)
a = b; //ditto
//a = b = c; //impossible here
a = c; //works
So, the modification of a has nothing to do with the return type of the assignment operator, but with its side-effects.
As for your second example, shorterString which gets two const-references and returns one of them, should obviously leave it const. And if you need to work with the result in a non-const way, you must use non-const arguments as well: string& shorterString(string& s1, string& s2). These two functions can be overloads, and the compiler will choose an appropriate one.
I was going through reference return and came across temporary objects. I don't understand how to identify them. Please explain using this example:
If a and b are objects of same class, consider binary operator+. If you use it in an expression such as f(a+b), then a+b becomes temporary object and f has to of form f(const <class name>&) or f(<class name>). It can't be of form f(<class name>&) However, (a+b).g() is perfectly alright where g() can even change contents of object returned by a+b.
When you say f(a + b), the parameter of f needs to bind to the value with which the function was called, and since that value is an rvalue (being the value of a function call with non-reference return type)*, the parameter type must be a const-lvalue-reference, an rvalue-reference or a non-reference.
By constrast, when you say (a + b).g(), the temporary object is used as the implicit instance argument in the member function call, which does not care about the value category. Mutable values bind to non-const and const member functions, and const values only bind to const member functions (and similarly for volatile).
Actually, C++11 did add a way to qualify the value category of the implicit instance argument, like so:
struct Foo()
{
Foo operator+(Foo const & lhs, Foo const & rhs);
void g() &; // #1, instance must be an lvalue
void g() &&; // #2, instance must be an rvalue
}
Foo a, b;
a.g(); // calls #1
b.g(); // calls #1
(a + b).g(); // calls #2
*) this is the case for an overloaded operator as in this example, and also for built-in binary operators. You can of course make overloaded operators which produce lvalues, though going against the common conventions would probably be considered very confusing.
Your confusion comes not from that you cannot identify temporary objects, in both cases result of a+b is temporary object, but wrong assumption that non const method requires lvalue and would not accept temporary object, which is not true.
For a simple case, think of following piece of code:
int func(int lhs, int rhs)
{
return lhs + rhs;
}
int main() {
int a = 1, b = 2, c = 3;
return func(a * c, b * c);
}
Because func takes two integers, the program must calculate the values of a * c and b * c and store them somewhere -- it can't store them in a or b or c. So the resulting code is equivalent to:
int lhsParam = a * c;
int rhsParam = b * c;
return func(lhsParam, rhsParam);
Again, at the end of func() we return a calculate value, lhs + rhs. The compiler must store it in a new place.
For integers and so forth this seems very simple, but consider instead
int function(std::string filename);
function("hello");
filename has to be a std::string, but you passed a const char*. So what the compiler does is:
std::string filenameParam = "hello"; // construct a new object
function(filenameParam);
just like the previous example, but this time it is hopefully clearer that we're constructing a temporary object.
Note: The convention of calling them "somethingParam" is just for clarity in this answer.
This is a follow up question from Calling constructor in return statement.
This a operator overload fun in a class.
const Integer operator+(const Integer& IntObject)
{
cout << "Data : " << this->data << endl;
return Integer(this->data + IntObject.data);
}
What is the relevance of const in the return type for such functions?
int main()
{
Integer A(1); //Create 2 object of class Integer
Integer B(2);
const Integer C = A + B; //This will work
Integer D = A + B; //This will also work
fun(A + B); //Will work
}
void fun(Integer F) {}
This is a case temporaries are not created during return step due to NRVO. The object to be returned is directly constructed on the callee's address.
Here's a better example:
struct Foo
{
void gizmo();
Foo const operator+(Foo const & rhs);
};
Now if you have a Foo x; Foo y;, then you cannot say:
(x + y).gizmo(); // error!
The constant return value means you cannot use it for non-constant operations. For primitive types this is not quite so relevant, because there aren't many non-constant operations you can perform on temporary objects, because lots of "interesting" operations (like prefix-++) aren't allowed on temporaries.
That said, with C++11 one should really try and adopt the new idiom of never returning constant values, since non-constant values are now amenable to move optimisations.
Some people used to suggest doing that, to prevent writing nonsense like A + B = C. However, in C++11 it can prevent some optimisations since it makes the return value unmovable. Therefore, you shouldn't do it.
In this case, it also prevents you from writing perfectly valid code like D = A + B + C, but that's just because the author forgot to declare the operator const.
There is no relevance in your code snippet, because you are making a copy of the returned value.
In general, it is difficult to find good reasons to return a const value. I can only see it having an effect in this type of expression, attempting to call a non-const method on a const temporary:
(someObject.someMethodReturningConstValue()).someNonConstMethod(); // error, calls non const method on const temporary
so you should only use it if you want to disallow calling non-const methods on temporaries. On the other hand, it kills move-semantics in C++11 so is discouraged.
I am trying to understand a program, which includes the following definition for a function f
void f(String S, const String& r)
{
}
Here String in the argument stands for a class. I am confused on the difference between the definitions of these two arguments: "String S" and "const String& r". S should represent an object of class String, then how about r?
In more detail, the f is defined as
void f(String S, const String& r)
{
int c1 = S[1]; // c1=s.operator[](1).operator char( )
s[1] ='c'; // s.operator[](1).operator=('c')
int c2 = r[1]; // c2 = r.operator[](1)
r[1] = 'd'; // error: assignment to char, r.operator[](1) = 'd'
}
This code snippet is to show how the operator overload, but these comments does not help me much. For instance, why r[1]='d' is nor correct? Thanks for helping understanding it.
const String& r is a constant reference to String r. Within the function, you access r just like a String. The difference is that it is actually a reference to the object passed to the function, while S will be a copy of the object passed to the function. You can almost think of it as if you are accessing r through a de-referenced pointer (though there is more to it than that).
Another way to look at it: The caller will see changes to r (if it wasn't const), while he will not see changes to S.
The const simply means the function f cannot modify r.
See also: https://isocpp.org/wiki/faq/references#overview-refs
This seems to be just an example, to show the difference between ways of passing parameters.
One real case where you might pass one parameter by value, is when you need a copy of the value anyway. Perhaps when concatenating the two strings.