A reference defines an alternative name for an object. A reference type “refers to”
another type. We define a reference type by writing a declarator of the form &d,
where d is the name being declared.
The next thing is a reference is not an object. Instead, a reference is just another name for an already existing object. So we'll use these references to pass the parameter by reference so that it directly effect the actual parameters.
Question:
What happens when we use a reference (&) before a function name?
I'm a little bit confused, as in my opinion it will return the alias of return (variable name). Or am I wrong?.
std::vector<std::string> &split(const std::string &s, char delim,
std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
In C++, when the ref-sign (&) is used before the function name in the declaration of a function it is associated with the return value of the function and means that the function will return by reference.
int& foo(); // Function will return an int by reference.
When not used within a declaration context, putting the ref-sign before a function name results in calling the address-of operator returning the address of the function. This can be used to e.g. create a pointer to a function.
// Some function.
int sum(int a, int b) {
return a + b;
}
int main() {
// Declare type func_ptr_t as pointer to function of type int(int, int).
using func_ptr_t = std::add_pointer<int(int, int)>::type;
func_ptr_t func = ∑ // Declare func as pointer to sum using address-of.
int sum = func(1, 2); // Initialize variable sum with return value of func.
}
In C, the only use of & is for the address-of operator. References does not exist in the C language.
In C, &func where func is a function evaluates to the address of the function which can be assigned to a function pointer which points to a function having the same signature as the function func.
int func(float);
int (*fp)(float) = &func;
// equivalent to
int (*fp)(float) = func;
'// return the plural version of word if ctr is greater than 1
string make_plural(size_t ctr, const string &word,
const string &ending)
{
return (ctr > 1) ? word + ending : word;
}'
The return type of this function is string, which means the return value is copied to
the call site. This function returns a copy of word, or it returns an unnamed
temporary string that results from adding word and ending.
As with any other reference, when a function returns a reference, that reference is
just another name for the object to which it refers. As an example, consider a function
that returns a reference to the shorter of its two string parameters:
'// return a reference to the shorter of two strings
const string &shorterString(const string &s1, const string
&s2)
{
return s1.size() <= s2.size() ? s1 : s2;
}'
The parameters and return type are references to const string. The strings are
not copied when the function is called or when the result is returned.
Never Return a Reference or Pointer to a Local Object
When a function completes, its storage is freed. After a function
terminates, references to local objects refer to memory that is no longer valid:
Related
I'm having the following code:
#include <string>
#include <cstdio>
std::string name = "Ternary Return Test";
std::string *pname = &name;
const std::string &getName ()
{
return pname ? *pname : "(unnamed)";
}
int main (int argc, char *argv[])
{
const std::string &str = getName();
printf ("Name is \"%s\"\n",str.c_str());
printf ("pName is \"%s\"\n",pname->c_str());
return 0;
}
The function getName() dereferences the pname pointer and returns it's value as a reference.
As I understand, returning reference to something, through dereferencing of a pointer is perfectly valid.
In order to avoid NULL pointer dereferencing, the function returns the string "unnamed", in the (in this situation impossible) case, when the pname pointer is NULL.
However, the ternary operator breaks the function. The code compiles, but prints following:
Name is "�
#"
pName is "Ternary Return Test"
The value, obtained through the function is broken. I cannot understand why.
In other situation, similar code produces segmentation fault. So, an undefined behaviour is happening here?
Yes, in the case when the pname would be NULL, it would return a reference to temporary, which is undefined. But this is not the case - I am returning a reference to a non-temporary value, which should be perfectly valid.
As I read, the ternary operator converts the third expression "(unnamed)" to the type of the second (std::string). But in my case, the third expression is not even used.
But this is not the case - I am returning a reference to a non-temporary value, which should be perfectly valid.
You would be, but you don't have a non-temporary value anymore. [expr.cond]/4.3 has
If E2 is a prvalue or if neither of the conversion sequences above can be formed and at least one of the operands has (possibly cv-qualified) class type:
if T1 and T2 are the same class type (ignoring cv-qualification) and T2 is at least as cv-qualified as T1, the target type is T2,
And what that boils down to is that since the third operand is a prvalue, the entire expression is a prvalue which mean you always have undefined behavior as you are always returning a reference to a temporary.
ternary operator type for
pname ? *pname : "(unnamed)" is std::string (we have std::string& and const char*)
So it is equivalent to pname ? std::string{*pname} : std::string{"(unnamed)"}.
So you return reference from temporary variable (in both cases) (and so dangling reference, leading to UB when you use it).
If you have used if instead of ternary, you would have your expected error
const std::string& getName()
{
if pname { return *pname; } // OK here
return "(unnamed)"; // Dangling pointer here
}
One solution might be;
const std::string &getName ()
{
static const std::string unnamed = "(unnamed)";
return pname ? *pname : unnamed;
}
So both sides are lvalue, and common type is now const std::string & (std::string & and const std::string&).
As Yksisarvinen points out, the problem is a lifetime issue. "(unnamed)" has static storage duration, but that's not what you return. You return std::string{"(unnamed)"}, and a reference to be exact. That unnamed temporary goes away before the function even returns.
Fix:
std::string const& getName ()
{
static const std::string defaultValue = "(unnamed)";
return pname ? *pname : defaultValue;
}
For reference (the dangling-reference UB is well described already), this should probably be something like
const std::string &getName ()
{
static const std::string unnamed("unnamed");
return pname ? *pname : unnamed;
}
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
}
C++ primer, 6.7 pointer to functions Using auto or decltype for Function Pointer Types
If we know which function(s) we want to return, we can use decltype to simplify
writing a function pointer return type. For example, assume we have two functions, both of which return a string::size_type and have two const string&
parameters. We can write a third function that takes a string parameter and returns a pointer to one of these two functions as follows:
string::size_type sumLength(const string&, const string&);
string::size_type largerLength(const string&, const string&);
// depending on the value of its string parameter,
// getFcn returns a pointer to sumLength or to largerLength
decltype(sumLength) *getFcn(const string &);
I don't understand "depending on the value of its string parameter, getFcn returns a pointer to sumLength or to largerLength".
How do I know the pointer function returns point to sumLength or largerLength?
The passage is saying you can define getFcn as such
typedef decltype(sumLength) func_type;
func_type* getFcn(const string& s)
{
if (s.size() < 1000) // magic number
return sumLength;
else
return largerLength;
}
And you can call it like
string str1, str2;
// calls either sumLength or largerLength with str1, str2
// depending on str1's size
auto i = getFcn(str1)(str1, str2);
Why these definitions are all ok:
int func(int p=255) {
return p;
}
int func1(const int &p=255) {
return p;
}
but this definition:
int func2(int &p=255) {
return p;
}
leads to compile error ?
What is the logic behind it ?
Taking arguments by reference means, you dont work with your local copy of the variable, but with a variable already defined in the scope of the calling function.
While your first example makes sense (you have a local variable p that you can fill with a default value) the second example is a bit more tricky: Usually when using references you expect the variable to have an address, since you want to modify it. For const-refernces, the compiler will still allow you to pass a literal, even if something like "reference to a literal" makes no sense at all.
In the third case the compiler expects you to modify p. But what part of the memory should this modification affect? "255" has no address - therefore it cant be used as a reference.
If you want to have a more detailed explanation, you should probably look for keywords like "rvalue" and "lvalue".
The attempted function definition
auto func2( int& p = 255 )
-> int
{ return p; }
… fails because you can't bind an rvalue to a reference to non-const. Basically that rule is because a simple value like 255 isn't modifiable. While the reference can be used to modify.
One simple solution is to express the default as a separate overload:
auto func2( int& p )
-> int
{ return p; }
auto func2()
-> int
{
int scratchpad = 255;
return func2( scratchpad );
}
A non-const reference must be bound to lvalue (i.e. its address could be got). 255 (i.e. an int literal) is not a lvalue, so int &p=255 fails.
A const reference could be bound to rvalue, and for this case, a temporary int will be created and initialized from 255. The temporary int's lifetime will be the same as the const reference.
int func(int p=255) {
return p;
}
p here is copied by value, and it is defined to exist in the scope of func.
int func2(int &p) {
return p;
}
// e.g. use:
int value = 10;
func2(value); // func2 *could* modify value because it is passed by non-const reference
In this case the compiler here expects p to have a name somewhere in memory (i.e. lvalue), so it can possibly write to it within func2. Passing by non-const reference allows you to modify the variable used in the function call. Since p must belong to someone else somewhere since it can be modified, you can't assign a default value to it.
But what about the const-reference case? Here, the compiler is smart enough to know that p can never be written to since it is const, so it doesn't need to have a name in memory to write to. In cases of a literal being passed (e.g. 255), it (behind the scenes) essentially creates a temporary and passes that temporary variable to the function.
int func1(const int &p=255) {
return p;
}
func1(10);
// Behind the scenes, the compiler creates something along these lines
// since it can never be modified.
const int some_temporary = 10;
func1(some_temporary);
I am a C guy and I'm trying to understand some C++ code. I have the following function declaration:
int foo(const string &myname) {
cout << "called foo for: " << myname << endl;
return 0;
}
How does the function signature differ from the equivalent C:
int foo(const char *myname)
Is there a difference between using string *myname vs string &myname? What is the difference between & in C++ and * in C to indicate pointers?
Similarly:
const string &GetMethodName() { ... }
What is the & doing here? Is there some website that explains how & is used differently in C vs C++?
The "&" denotes a reference instead of a pointer to an object (In your case a constant reference).
The advantage of having a function such as
foo(string const& myname)
over
foo(string const* myname)
is that in the former case you are guaranteed that myname is non-null, since C++ does not allow NULL references. Since you are passing by reference, the object is not copied, just like if you were passing a pointer.
Your second example:
const string &GetMethodName() { ... }
Would allow you to return a constant reference to, for example, a member variable. This is useful if you do not wish a copy to be returned, and again be guaranteed that the value returned is non-null. As an example, the following allows you direct, read-only access:
class A
{
public:
int bar() const {return someValue;}
//Big, expensive to copy class
}
class B
{
public:
A const& getA() { return mA;}
private:
A mA;
}
void someFunction()
{
B b = B();
//Access A, ability to call const functions on A
//No need to check for null, since reference is guaranteed to be valid.
int value = b.getA().bar();
}
You have to of course be careful to not return invalid references.
Compilers will happily compile the following (depending on your warning level and how you treat warnings)
int const& foo()
{
int a;
//This is very bad, returning reference to something on the stack. This will
//crash at runtime.
return a;
}
Basically, it is your responsibility to ensure that whatever you are returning a reference to is actually valid.
Here, & is not used as an operator. As part of function or variable declarations, & denotes a reference. The C++ FAQ Lite has a pretty nifty chapter on references.
string * and string& differ in a couple of ways. First of all, the pointer points to the address location of the data. The reference points to the data. If you had the following function:
int foo(string *param1);
You would have to check in the function declaration to make sure that param1 pointed to a valid location. Comparatively:
int foo(string ¶m1);
Here, it is the caller's responsibility to make sure the pointed to data is valid. You can't pass a "NULL" value, for example, int he second function above.
With regards to your second question, about the method return values being a reference, consider the following three functions:
string &foo();
string *foo();
string foo();
In the first case, you would be returning a reference to the data. If your function declaration looked like this:
string &foo()
{
string localString = "Hello!";
return localString;
}
You would probably get some compiler errors, since you are returning a reference to a string that was initialized in the stack for that function. On the function return, that data location is no longer valid. Typically, you would want to return a reference to a class member or something like that.
The second function above returns a pointer in actual memory, so it would stay the same. You would have to check for NULL-pointers, though.
Finally, in the third case, the data returned would be copied into the return value for the caller. So if your function was like this:
string foo()
{
string localString = "Hello!";
return localString;
}
You'd be okay, since the string "Hello" would be copied into the return value for that function, accessible in the caller's memory space.
Your function declares a constant reference to a string:
int foo(const string &myname) {
cout << "called foo for: " << myname << endl;
return 0;
}
A reference has some special properties, which make it a safer alternative to pointers in many ways:
it can never be NULL
it must always be initialised
it cannot be changed to refer to a different variable once set
it can be used in exactly the same way as the variable to which it refers (which means you do not need to deference it like a pointer)
How does the function signature differ from the equivalent C:
int foo(const char *myname)
There are several differences, since the first refers directly to an object, while const char* must be dereferenced to point to the data.
Is there a difference between using string *myname vs string &myname?
The main difference when dealing with parameters is that you do not need to dereference &myname. A simpler example is:
int add_ptr(int *x, int* y)
{
return *x + *y;
}
int add_ref(int &x, int &y)
{
return x + y;
}
which do exactly the same thing. The only difference in this case is that you do not need to dereference x and y as they refer directly to the variables passed in.
const string &GetMethodName() { ... }
What is the & doing here? Is there some website that explains how & is used differently in C vs C++?
This returns a constant reference to a string. So the caller gets to access the returned variable directly, but only in a read-only sense. This is sometimes used to return string data members without allocating extra memory.
There are some subtleties with references - have a look at the C++ FAQ on References for some more details.
#include<iostream>
using namespace std;
int add(int &number);
int main ()
{
int number;
int result;
number=5;
cout << "The value of the variable number before calling the function : " << number << endl;
result=add(&number);
cout << "The value of the variable number after the function is returned : " << number << endl;
cout << "The value of result : " << result << endl;
return(0);
}
int add(int &p)
{
*p=*p+100;
return(*p);
}
This is invalid code on several counts. Running it through g++ gives:
crap.cpp: In function ‘int main()’:
crap.cpp:11: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int*’
crap.cpp:3: error: in passing argument 1 of ‘int add(int&)’
crap.cpp: In function ‘int add(int&)’:
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:20: error: invalid type argument of ‘unary *’
A valid version of the code reads:
#include<iostream>
using namespace std;
int add(int &number);
int main ()
{
int number;
int result;
number=5;
cout << "The value of the variable number before calling the function : " << number << endl;
result=add(number);
cout << "The value of the variable number after the function is returned : " << number << endl;
cout << "The value of result : " << result << endl;
return(0);
}
int add(int &p)
{
p=p+100;
return p;
}
What is happening here is that you are passing a variable "as is" to your function. This is roughly equivalent to:
int add(int *p)
{
*p=*p+100;
return *p;
}
However, passing a reference to a function ensures that you cannot do things like pointer arithmetic with the reference. For example:
int add(int &p)
{
*p=*p+100;
return p;
}
is invalid.
If you must use a pointer to a reference, that has to be done explicitly:
int add(int &p)
{
int* i = &p;
i=i+100L;
return *i;
}
Which on a test run gives (as expected) junk output:
The value of the variable number before calling the function : 5
The value of the variable number after the function is returned : 5
The value of result : 1399090792
One way to look at the & (reference) operator in c++ is that is merely a syntactic sugar to a pointer. For example, the following are roughly equivalent:
void foo(int &x)
{
x = x + 1;
}
void foo(int *x)
{
*x = *x + 1;
}
The more useful is when you're dealing with a class, so that your methods turn from x->bar() to x.bar().
The reason I said roughly is that using references imposes additional compile-time restrictions on what you can do with the reference, in order to protect you from some of the problems caused when dealing with pointers. For instance, you can't accidentally change the pointer, or use the pointer in any way other than to reference the singular object you've been passed.
In this context & is causing the function to take stringname by reference.
The difference between references and pointers is:
When you take a reference to a variable, that reference is the variable you referenced. You don't need to dereference it or anything, working with the reference is sematically equal to working with the referenced variable itself.
NULL is not a valid value to a reference and will result in a compiler error. So generally, if you want to use an output parameter (or a pointer/reference in general) in a C++ function, and passing a null value to that parameter should be allowed, then use a pointer (or smart pointer, preferably). If passing a null value makes no sense for that function, use a reference.
You cannot 're-seat' a reference. While the value of a pointer can be changed to point at something else, a reference has no similar functionality. Once you take a variable by reference, you are effectively dealing with that variable directly. Just like you can't change the value of a by writing b = 4;. A reference's value is the value of whatever it referenced.