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
}
Related
My code is the following:
void parentheses (int n, string& str, int left, int right){
... irrelevant...
}
void solve(int n){
parentheses(n,"",0,0);
}
However, this will give me an error, telling me that cannot bind non-const lvalue reference of type std::__cxx11::string& ... to an rvalue of type ‘std::__cxx11::string. In this case, if I still want to pass the string in as a reference, how should I modify my functions? I don't want to make them const because I want to functions to modify the original string, and I want them to be & precisely because I want to edit their values.
The function parentheses expects an lvalue in the std::string parameter, i.e. a named variable. However, you have supplied an rvalue (temporary) in this call:
parentheses(n,"",0,0);
An empty string object is created and passed to parentheses. You can avoid this problem by changing the definition of parentheses like so:
void parentheses (int n, const string& str, int left, int right)
Here str will bind to an rvalue/temporary, but you won't be able to change its value in the function. However, if you want to change the value of str you have to define a string variable and pass that to the function.
Example:
void solve(int n){
std::string str;
parentheses(n,str,0,0);
}
Note: no need to assign str to "" as a string is empty by default.
the function needs a memory to change, you didn't specify which.
declare a string to hold what you want to pass and where to get the output to.
string s = "";
and pass it to the function
I'm not really sure what the purpose is of passing "" by reference is, as any value put there will get lost.
Anyway, to answer your question, create a variable and pass it instead:
void solve(int n){
std::string tmp = "";
parentheses(n,tmp,0,0);
}
If you don't care about the value stored in tmp, you can just ignore it. But you need some type of variable there, even if you don't care about what gets eventually put there by the routine.
Your parentheses() function takes a non-const reference to a std::string object, so it expects an actual std::string object on the other side of the reference - an lvalue (something that can be assigned to).
But your solve() function is not passing a std::string object, it is passing a string literal instead. So the compiler creates a temporary std::string object - an rvalue - which then fails to bind to the reference, because a temporary object can't be bound to a non-const reference, only to a const reference. That is what the error message is telling you:
cannot bind non-const lvalue reference of type std::__cxx11::string& ... to an rvalue of type ‘std::__cxx11::string
solve() needs to explicitly create an actual std::string object to pass to parentheses():
void solve(int n){
std::string s = "";
parentheses(n,s,0,0);
}
If you want to change the values of your string for any string that is passed as a paramenter (lvalue, as well rvalue), just initialize a variable with the intended content and pass it to your function.
But if you want to treat lvalue strings diferently from rvalue strings, just overload your original function. i.e.:
void parentheses (int n, string& str, int left, int right){
... irrelevant... // change strings values as desired
}
void parentheses (int n, string&& str, int left, int right){
... irrelevant... // string as rvalue
}
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.
I am trying to push a string in a string vector, like below
void Node::set_val(string &val)
{
this->val.push_back(val);
}
But when I try to call it as below
Obj.set_val("10h;");
I get the below error,
error: no matching function for call to 'Node::set_val(const char [5])'
I assumed that the string in " " is same as string in c++, Why do I get such an error? What has to be changed below?
You are taking in a std::string by non-const reference. Non-const references cannot bind to rvalues, like "10h;", so you can't pass literals in to that function.
If you aren't going to modify the argument, you should take your argument by reference-to-const:
void Node::set_val(const string &val)
// ^^^^^
This way, a temporary std::string will be constructed from your const char[5] and passed in to set_val.
You could improve this by taking in the string by value and moveing it into the vector:
void Node::set_val(string val)
{
this->val.push_back(std::move(val));
}
This prevents you from making some unnecessary copies.
So in C++, const char* is implicitly convertible to std::string because std::string has a (non-explicit) constructor that takes const char*. So what the compiler tries here is to create a temporary std::string object for your function call, like so:
Node.set_val(std::string("10h;"));
However, since you declared the parameter of set_val to be a non-const reference to a std::string, the compiler can't make this conversion work due to the fact that temporary objects can't be bound to non-const references.
There are three ways to make this work, depending on what you want to achieve:
void Node::set_val(const std::string& val) {}
void Node::set_val(std::string val) {}
void Node::set_val(std::string&& val) {}
All will compile (the last one requires C++11 or higher), but seeing your use case, I would recommend to use the second or third one. For an explanation why, try reading a little bit about move semantics in C++11.
The important thing to take away here is that const char* implicitly converts to std::string by creating a temporary object, and temporary objects can't be passed to functions taking non-const references.
You are passing "10h;" which is a const char array.
Fix it by passing a string: Obj.set_val(string("10h")); and edit function to take a string by value:
void Node::set_val(string val) { /* */ }
Or maybe better, edit your function to take a const string&:
void Node::set_val(const string &val) { /* */ }
The code below:
void test(string &s){ // if the argument is "string s", it works
return test(s+',');
}
The compiler reports cannot find the function: test(std::basic_string).
I think the compiler would create a temporary string (== s+','), and I can pass its reference.
But it seems I am wrong. I do not know why I cannot pass the reference of this temporary string.
You can't bind a temporary to a non-constant reference. You could either take the argument by const reference (or, as you point out, by value)
void test(string const & s){ // or string s
return test(s+',');
}
or use a named variable rather than a temporary
void test(string & s){
std::string s2 = s + ',';
return test(s2);
}
As noted, at great length, in the comments, this code has undefined runtime behaviour and shouldn't be used in "real" code; it's purpose is just a minimal example of how to fix the observed compilation error
make it const:
void test(const std::string &s){ // if the argument is "string s", it works
return test(s+',');
}
But first you should have seen this question String Concatenation
concatenating strings using "+" in c++
Alternative Solution
void test(string &s)
{
s.append(",");
return test(s);
}
Standard C++ does not allow a non-const lvalue reference to be bound to an rvalue. In your example, the result of the expression s+',' is a temporary and thus an rvalue, so the compiler is required to discard the overload of test expecting an lvalue reference, leaving it no overload available to call. That's why it complains about not being able to find the function test.
To solve this issue you have to provide an overload whose parameter may be bound to an rvalue. As you realized yourself, expecting an argument by-copy works, but it may imply unnecessary overhead by calling copy/move-ctors. A better option would be to expect the argument by reference. Since const lvalue references may be bound to rvalues, declaring the function as follows solves the problem.
void test(std::string const& s)
My function declaration is
siteObject(std::string& url, std::string& get, std::string& post);
So why is this site("String 1", "String 2", "String 3"); creating a mismatch type error. It says it wants a string reference and it's receiving a char array. If you need more detail just ask in the comments.
Because there's an implicit call to the std::string constructor, which creates a temporary object. You cannot take a non-const reference to a temporary (because it's meaningless to modify a temporary).
So, either modify your function to take const references, or by-value, or pass it non-temporary objects.
Your siteObject function:
siteObject(std::string& url, std::string& get, std::string& post);
takes non-const references to string objects, which cannot be bound to rvalues (or temporaries).
When you try to call the function with string literals, the compiler has to convert those arguments (which are char*) to something that matches the parameter types - that conversion results in a temporary std::string object.
You'll need to change your function to accept const references if you want to be able to bind them to temporaries:
siteObject(std::string const& url, std::string const& get, std::string const& post);
Or you could pass values instead of references:
siteObject(std::string url, std::string get, std::string post);
You need to either make your function accept const std::string& str or construct string instances to pass in, and not rely on the implicit conversion of char* to string objects.
The correct call is:
std::string url("...");
std::string get("...");
std::string post("...");
siteObject(url, get, post);
This makes sense since the method signature implies that you get something back in the three strings (non-const references) and you may use those return values.
If that's not the intention and you have the ability to change the siteObject() method then you should do:
siteObject(std::string const & url, std::string const & get, std::string const & post);
and use your original call.
Strings entered in double quote characters are coming from the C heritage of C++ (they are called C string or NUL terminated string). They are implemented by the compiler as array of char. On the contrary, the std::string is a C++ class that aims to simplify manipulation of strings. It owns a C string (and can be created from one since it has a constructor that accept a const char*), and manage its memory.
Since there exists a construtor of std::string from const char* and that C string are compatible with that type, how come the compiler cannot call this function ? This is because the function is taking non-const reference to std::string objects. The constructor can't be used in this situation because the objects created would be temporaries, and you cannot get a non-const reference to a temporary object, as the called function may mutate it.
You can either create the std::string and pass them to the function:
std::string s1("String 1");
std::string s2("String 2");
std::string s3("String 3");
site(s1, s2, s3);
Or you can change the prototype of the site function to accept const reference. This is only possible if the function does not mutate the objects and you have access to the code:
// Declaration
void site(const std::string& s1, const std::string& s2, const std::string s3);
// Usage
site("String 1", "String 2", "String 3");