Why use dereferencing when function takes arguments in C++ [duplicate] - c++

This question already has answers here:
What is the meaning of & in c++?
(6 answers)
Closed 4 years ago.
#include <iostream>
using namespace std;
class Dummy {
public:
bool isitme (Dummy& param);
};
bool Dummy::isitme (Dummy& param)
{
if (&param == this) return true;
else return false;
}
int main () {
Dummy a;
Dummy* b = &a;
if ( b->isitme(a) )
cout << "yes, &a is b\n";
return 0;
}
I was looking at this C++ example and I don't understand why bool isitme (Dummy& param); uses the dereferencing sign '&'. The argument is an Dummy object itself right, why it is the object's address?

Ampersand is not the "dereferencing sign". It is used here in two different ways which I will explain below.
The "dereference sign" is asterisk (*).
bool Dummy::isitme (Dummy& param)
Here, Dummy& param means that param is a reference to a Dummy object.
if (&param == this) return true;
Here, &param denotes address of param.

The isitme takes its argument by reference that is it takes the address of the object instead of copying it. The point is not to copy the object and to work on the original one.

Related

Use case for `&` ref-qualifier? [duplicate]

This question already has answers here:
What's a use case for overloading member functions on reference qualifiers?
(4 answers)
Closed 10 months ago.
I just discovered this is valid C++:
struct S {
int f() &; // !
int g() const &; // !!
};
int main() {
S s;
s.f();
s.g();
}
IIUC, this is passed to f by reference and to g be passed by const-reference.
How was this useful to anyone?
They are useful for both providing safety and optimizations.
For member functions returning a pointer to something they own (either directly or via view types like std::string_view or std::span), disabling the rvalue overloads can prevent errors:
struct foo {
int* take_ptr_bad() { return &x; }
int* take_ptr() & { return &x; }
int x;
};
foo get_foo();
void bar() {
auto ptr = get_foo().take_ptr_bad();
// ptr is dangling
auto ptr = get_foo().take_ptr();
// does not compile
}
The other is to provide some optimizations. For instance, you might overload a getter function to return an rvalue reference if this is an rvalue to prevent unnecessary copies:
struct foo {
const std::string& get_str() const & {
return s;
}
std::string&& get_str() && {
return std::move(s);
}
std::string s;
};
void sink(std::string);
foo get_foo();
void bar() {
sink(get_foo().get_str());
// moves the string only if the r-value overload is provided.
// otherwise a copy has to be made, even though the foo object
// and transitively the string is temporary.
}
These are how I use the feature, and I'm sure there are more use cases.

What's the meaning of a prototype ending with a & (ampersand) [duplicate]

This question already has answers here:
What is "rvalue reference for *this"?
(3 answers)
Closed 4 years ago.
By mistake, I had a & at the end of a prototype (see example below). Neither gcc nor Clang complains about it. I noticed that the symbol generated is not exactly the same.
Example:
class A
{
public:
void fn() &
{
return;
}
};
int main()
{
A a;
a.fn();
return 1;
}
Name of the symbol without &: _ZN1A2fnEv and with &: _ZNR1A2fnEv.
What does it mean ? Do I miss something ?
Thanks,
The & at the end of the member function declaration is a ref qualifier. It applies to the object value on which the member function is called, and constrains that value's value category:
Functions without ref qualifiers can be called on any value.
Functions with & qualifier can only be called on lvalues.
Functions with && qualifier can only be called on rvalues.
The ref qualifier affects overload resolution, e.g. an overload on a mismatched instance value is not viable.
The standard library doesn't use ref qualifiers much (I can only think of std::optional), so let's make up our own example:
struct X {
explicit X(int n) : s_(n, 'a') {}
std::string s_;
const char* f1() const { return s_.c_str(); }
const char* f2() const & { return s_.c_str(); }
const char* f3() const && { return s_.c_str(); }
};
Now consider the following calls:
int main() {
X x(10);
x.f1(); // OK
X(20).f1(); // OK
x.f2(); // OK
X(20).f2(); // ill-formed
x.f3(); // ill-formed
X(20).f3(); // OK
}
The example also demonstrates why this feature may be useful: When a member function returns a reference to some internal part of the object itself, then it is important that that internal reference does not outlast the lifetime of the object. If your member function is unqualified, then you can very easily introduce lifetime bugs. For example:
const char* s = std::string("abcde").c_str(); // dangling pointer!
One way to improve such "internal state access" APIs is to create different return value (categories) for different ref-qualified overloads. To get back to std::optional, the engaged-access essentially boils down to this set of overloads:
struct MyOptional {
T value_; // assume engaged!
T& get() & { return value_; }
T&& get() && { return std::move(value_); }
};
That means that MyOptional::get returns an lvalue when invoked on an lvalue optional, and an rvalue (in fact an xvalue) when invoked on an rvalue. This means that, given MyOptional x;, the binding T& r = x.get(); is allowed, but T& r = MyOptional().get(); is not, and similarly T&& r = x.get(); is disallowed, but T&& r = std::move(x).get() is allowed.

Checking if a parameter passed to a member function is the object itself

#include <iostream>
using namespace std;
class Dummy {
public:
bool isitme (Dummy& param);
};
bool Dummy::isitme (Dummy& param)
{
if (&param == this) return true;
else return false;
}
int main () {
Dummy a;
Dummy* b = &a;
if ( b->isitme(a) )
cout << "yes, &a is b\n";
return 0;
}
Regarding the code above, in 'isitme' function, the if condition:
if (&param == this)
Shouldn't be:
if (param == this)
as 'this' is a pointer, and 'param' is a pointer too, so if we said:
if (&param == this)
that would be a comparison between an address of a pointer (&param) and a pointer (this), which is not what we are looking for; checking if a parameter passed to a member function is the object itself?
A reference type doesn't have the same semantics with a pointer type. Its unspecified how compilers implement references. A reference type doesn't have an address per say. When you take the address of a reference type the result will always be the address of the object it was bound to.
So the code below tests the original object's address param binded to with this;
bool Dummy::isitme (Dummy& param)
{
if (&param == this) return true;
else return false;
}
In the case of pointers, just test the pointers for equality.
bool Dummy::isitme (Dummy* param)
{
if (param == this) return true;
else return false;
}

Why is const sometimes part of the function signature? [duplicate]

This question already has answers here:
Functions with const arguments and Overloading
(3 answers)
Closed 6 years ago.
Why does const create a different signature when its applied to a struct pointer as opposed to a struct?
E.g.
typedef struct test_s {
int foo;
} test;
void foo(test *ptr){
return;
}
// This is ok
void foo(const test *ptr){
return;
}
void foo(test t){
return;
}
//This is an error
void foo(const test t){
return;
}
(tested on gcc version 4.9.2)
To be more specific, why is it that the bottom one is an error when the pair with the pointers is not an error. The referenced duplicate question (Functions with const arguments and Overloading) would also seem to argue that the case with the pointers should be duplicates.
void foo(const test t){
return;
}
is an error since it is the same as:
void foo(test t){
return;
}
which makes it a duplicate of the previous function.
When the argument to a function is test*, you can dereference the pointer and modify it. The modification will be visible in the calling function.
void foo(test *ptr){
ptr->foo = 10; // The state of the object in the calling function
// is changed.
return;
}
When the argument to a function is const test*, you can dereference the pointer to access it but not modify it.
void foo(const test *ptr){
std::cout << ptr->foo << std::endl; // OK
ptr->foo = 10; // Not OK
return;
}
For the same reason, you can overload:
void foo(test& t);
void foo(const test& t);
When you try to overload
void foo(test t);
void foo(const test t);
Both are equally good candidates when you call it. The compiler cannot disambiguate between the two. In addition, take a look at one of the answers to the dupe. It cites the section of the C++ standard that states why the last two are equivalent.

Need to understand when parameters passed as (className& arg) in c++ [duplicate]

This question already has answers here:
"const T &arg" vs. "T arg"
(14 answers)
What are the differences between a pointer variable and a reference variable?
(44 answers)
Closed 7 years ago.
// const objects
#include <iostream>
using namespace std;
class MyClass {
int x;
public:
MyClass(int val) : x(val) {}
const int& get() const {return x;}
};
void print (const MyClass& arg) { // Need to understand this line
cout << arg.get() << '\n';
}
int main() {
MyClass foo (10);
print(foo);
return 0;
}
I am new to C++. Need to understand what are the parameters passed in print function. If this is address then why are we passing foo is print function call.
The & in void print (const MyClass& arg) that arg is passed by reference. It is C++s way to make pointers and things a little bit easier.
References allow you to manipulate a variable inside of a function and make the results visible on the outside too. So a bit like pointers. But you don't need to explicitly get the address of the variable to do that.
The const statement is a way to prevent the described behavior. const forbids the manipulation of arg inside print.