1st code:
#include <iostream>
using namespace std;
class demo
{
int a;
public:
demo():a(9){}
demo& fun()//return type isdemo&
{
return *this;
}
};
int main()
{
demo obj;
obj.fun();
return 0;
}
2nd code:
#include <iostream>
using namespace std;
class demo
{
int a;
public:
demo():a(9){}
demo fun()//return type is demo
{
return *this;
}
};
int main()
{
demo obj;
obj.fun();
return 0;
}
what is the difference between these two codes as both are working in gcc?i am new here so forgive me if my way of asking is wrong.
demo & fun() returns a reference to the current object. demo fun() returns a new object, made by copying the current object.
Both are valid but are different. In the first case demo& fun() a reference to the same object is returned, in the second case a new object is created. While both are the same, the semantics differ, run this example:
#include <iostream>
struct test {
int x;
test() : x() {}
test& foo() { return *this; }
test bar() { return *this; }
void set( int value ) { x = value; }
};
int main() {
test t;
t.foo().set( 10 ); // modifies t
t.bar().set( 5 ); // modifies a copy of t
std::cout << t.x << std::endl; // prints 10
}
Apart from what #Erik said about the return type, a little excursus on the this-pointer:
The following is equivalent:
struct my_struct{
my_struct* get_this() const { return this; }
};
my_struct obj;
my_struct* obj_this = ob.get_this();
std::cout << std::boolalpha; // to display true/false instead of 1/0
std::cout << "&obj == obj_this = " << &obj == obj_this << "\n";
The this pointer is just the pointer to that object, you can think of it as a hidden parameter. It's more understandable in the C way:
typedef struct my_struct{
int data;
// little fidgeting to simulate member functions in c
typedef void (*my_struct_funcptr)(struct my_struct*,int);
my_struct_funcptr func;
}my_struct;
// C++ does something similar to pass the this-pointer of the object
void my_struct_func(my_struct* this, int n){
this->data += n;
}
my_struct obj;
obj.data = 55;
// see comment in struct
obj.func = &my_struct_func;
obj.func(&obj, 15);
// ^^^^ - the compiler automatically does this for you in C++
std::cout << obj.data; // displays 70
Consider your function.
demo fun(){return *this;}
Here you are returning by value so one temporary object will be created which will be destroyed, once you assign the return value of fun to some other object.
While in case when you pass the reference, no object will be created newly, but it will pass actual object and even after assigning function return value object will not destroy till main object(used inside fun, in ur case its the object calling the function) won't go out of scope.
The concept you are trying to understand can be explained in more detail with other example.
consider function that is taking object as argument and returning object as argument.(also consider we have object that contains a pointer, we will assign value to pointer by first allocating memory to pointer and a destructor, which will free memory hold by pointer of object). Now when you return object as pass by value, temporary object will be created, that will have exact copy of main object(and temporary object's pointer will also point to same address or you can say holds the same address). Now inside main(), you assign/initialize any object with return value(object) of function. But when your temp object will be destroyed after assigning value, it will also free the memory because of destructor and when you try to fetch the same address value through assigned object(inside main() ) you will get error as that memory has been already freed.
But if you would have return value using reference, object returned by object won't destroy as main obj(inside function or through which we have called the function) is in scope and your pointer won't loose its memory. Making possible for assigned object to fetch address value through its pointer and avoid undesirable result.
In code 1 demo obj creates a fresh copy of demo. obj is initialised using demo's default constructor 'demo():a(9){}'. obj.fun() returns a reference to (already existing) obj.
In code 2 obj.fun() creates a new demo type object using demo's copy constructor (in your case it is compiler generated) and returns that copy to the caller.
Both code are valid.
1st code fun() is returning a reference to current object
2nd code fun() is returning the copy (by value) of the object
For 1st case, If you decide to return by value
then prefer to return a const
reference; i.e. const demo& fun();
and later you can copy it if needed.
Simply returning reference makes the
object modifiable, which may
accidently edit the content without
intent
For 2nd case, Do NOT return the object by value,
because it can create unnecessary
temporary copy which will effect
the memory/performance of your code
Related
It is said that constructor doesnot return anything.But if constructor doesnot return anything, then how do this code segment works:
*this=classname{args};.
I hope someone could shed me some light on whats actually going under the hood.
A complete code:
#include <iostream>
using namespace std;
class hell {
private:
int a{}, b{};
public:
hell(int _a = 7, int _b = 8) : a{ _a }, b{ _b } {}
void print() {
cout << a << endl << b << endl;
}
void change() {
*this = hell(4, 5);
}
};
int main() {
hell h;
h.print();
h.change();
h.print();
return 0;
}
The statement
*this = hell(4, 6);
does two things:
First it create a temporary and unnamed object of the class hell, initialized using the values you use to pass to a suitable constructor.
Then that temporary and unnamed object is copy-assigned to the object pointed to by this.
It's somewhat similar to this:
{
hell temporary_object(4, 5); // Create a temporary object
*this = temporary_object; // Copy the temporary object to *this
}
Your question must be about this line:
*this = hell(4,5);
This might look like a function call, calling the constructor function. But this is not a function call. This is (a particular) syntax for creating a new hell object, a temporary object. This is slightly outdated syntax, modern C++ prefers:
*this = hell{4, 5};
but it's the same thing.
This does call the constructor, but only as part of constructing a new object.
Once the temporary object gets constructed it gets assigned to *this. The End.
For better intuition, constructor can be called "initializator". This reveals more of it's main purpose. The constructor initializes object rather then creates. So the instance of the object is already present in the memory when the constructor is called. All it does is initializing it.
Lets consider the following piece of code:
template<typename T>
void f(std::unique_ptr<T>&& uptr) { /*...*/ }
In another function:
void g()
{
std::unique_ptr<ANY_TYPE> u_ptr = std::make_unique<ANY_TYPE>();
f(std::move(u_ptr));
X: u_ptr->do_sth(); // it works, I don't understand why. Details below.
}
I don't understand why u_ptr in line X is still alive.
After all I forced him to be moved (std::move).
---EDIT---
Ok, so now:
The code is still working:
class T{
public:
T(){}
void show(){
std::cout << "HEJ!\n";
}
};
void f(std::unique_ptr<T> ref){
ref->show();
}
int main()
{
std::unique_ptr<T> my;
my->show();
f(std::move(my));
my->show(); // How is it possible. Now, f takes unique_ptr by value
return 0;
}
You didn't show us that code to function f, but presumably it didn't move the pointer, even though it had permission to.
You passed the unique_ptr by reference. If function invocation actually moved it, then the function couldn't use it because it would be gone before the function had a chance to.
If you want function invocation to actually move the pointer, you need to pass the pointer by value, not be reference. That value would be a unique_ptr for it to be moved into. In that case, you should declare the function as taking a std::unique_ptr<T> instead of a std::unique_ptr<T>&&. Then you can actually invoke the move constructor when you call the function.
Update: With your latest change, the unique_ptr would no longer reference any valid object due to the move construction. You just never check that it does. Invoking a non-virtual method that doesn't access any member variables can work just the same whether the object is valid or destroyed because it doesn't need anything from the object. You also never made the unique_ptr actually point to anything.
Instead, make the unique_ptr point to something. After it's moved, try calling a virtual function or accessing a member whose value is changed by the destructor. Like this:
#include <iostream>
#include <memory>
class T{
public:
T() : valid (true) {}
~T() { valid = false; }
bool valid;
void show(){
std::cout << "HEJ! " << valid << std::endl;
}
};
void f(std::unique_ptr<T> ref){
ref->show();
}
int main()
{
std::unique_ptr<T> my (new T); // Make it point to a new object
my->show();
f(std::move(my));
my->show(); // Try to access
return 0;
}
in the line f(std::unique_ptr<T>&& uptr) uptr is not an object - it's a reference. a reference which capable to catch temporeries and mutate them.
it's like asking why doesn't the object get cloned in the next example
void func(std::string& str);
std::string str_ = "yyy";
func(str_);
str_ is passed by "regular" reference and won't get copied - this is what pass by reference means.
std::move only cast l-value to r-value-reference, which uptr in f(std::unique_ptr<T>&& uptr) can reference, it's a reference referencing an object. opposed to the common conception, std::move won't do any moving by itself, only casts the object to r-value-reference for the move constructor/assg. operator to kick in.
here, the pointer still holds valid data since it was not moved, only casted to r-value-reference.
if you want the object to move you have to declare the parameter as object, not reference : f(std::unique_ptr<T> uptr)
In your edit, you have undefiend behaviour, so everything may occure.
The reason why your call to show doesn't crash is because it doesn't use the this pointer (it doesn't try to modify or access a data member).
Try this:
class T{
public:
int v;
T(){}
void show(){
v = 0;
std::cout << "HEJ!\n";
}
};
void f(std::unique_ptr&& ref)
This is the answer when you initially had your f function taking a rvalue reference &&.
Your function takes a rvalue reference. Therefore, no new unique_ptr object is created yet, you are simply passing a reference.
Inside your f function, if you create a a local unique_ptr, with the parameter uptr, then finally uptr will be moved to create that new object.
template<typename T>
void f(std::unique_ptr<T>&& uptr)
{
//move uptr into local_unique_ptr
//note that we have to use move again
//because uptr has a name, therefore its a lvalue.
auto local_unique_ptr = std::unique_ptr<T>(std::move(uptr));
}
The important thing to always know is that std::move is simply a static_cast.
If you pass a lvalue to std::move, it returns a rvalue. If you pass a rvalue, it returns a rvalue. That's it.
Your function f may not in fact move the pointer. Merely taking an object by && does not modify the object.
u_ptr->do_sth() may invoke a static member function or a member function that does not access the object (this) and this is why it does not crash.
I don't understand quite well how to make class/structure which will be like this:
std::stringstream ss;
ss.str().c_str();
I would like to do something similar like this, example:
int result = MyAssignFunction(10, 5).AddParametrs();
// or
int result = MyAssignFunction(10, 5).FirstParametr;
I cannot name this thats why I cannot find any hints.
The main question is that is even possible or not? Please give me any hint.
The function MyAssignFunction needs to return an object that have an AddParametrs member function or a FirstParametr member variable.
But you need to be aware of that the object returned by MyAssignFunction in your examples is temporary. As soon as the expression is over, then it will be destructed.
A very simple example:
#include <iostream>
struct S
{
int value;
S(int initial) : value(initial) {}
S& add1() { value++; return *this; }
S& add2() { value += 2; return *this; }
S& addN(int n) { value += n; return *this; }
int get() const { return value; }
};
int main()
{
std::cout << "Operation = " << S(0).add1().add2().add1().addN(5).get() << '\n';
}
The above little dummy program will print
Operation = 9
The expression that does the "magic" is S(0).add1().add2().add1().addN(5).get(). It first creates a (temporary) object of the structure S and passes 0 to the constructor. Then on this object we call the member function add1, which returns a reference to itself, and on that reference we call add2, and so on. Finally we call the member function get to get the final value and output it.
As you can see, we can chain any number of function calls and in any order.
The above is just a very simple example, that allows the object to chain calls on itself. A member function can return another object (or reference to), and you can then chain calls to member function of that object. That is what you are seeing in your stringstream example: The str function returns a std::string object, and you call c_str on that std::string object.
If you are looking for method chaining meaning that you can reuse the output of a function call as if it were the object your function was called upon, all you need to do is return *this. Therefore your return value should be of the class type you are trying to implement method chaining on. To avoid an unnecessary invocation of the copy constructor, you should also return by reference. Here is a little example:
#include <iostream>
class A{
A& foo(){
return *this;
}
int bar(){
return 3;
}
};
int main(){
A a;
std::cout << a.foo().foo().foo().foo().bar(); //prints 3
}
Why is answer "OK"?
class CTest {
public:
int isitme(CTest& cobj);
};
int CTest::isitme(CTest &cobj)
{
if(&cobj == this)
{
return true;
}
else
{
return false;
}
}
int main()
{
CTest a;
CTest *b = &a;
if(b->isitme(a))
{
cout<<"OK";
}else
{
cout<<"not OK";
}
return 0;
}
Because a member function implicitly receives as an argument a pointer to the object it is invoked on. This pointer is made available within the body of the function as the this pointer.
So when you do:
b->isitme(a)
The member function isitme() implicitly receives the pointer b as an argument, and that pointer will be seen as the this pointer inside the function.
Since b points to a, this will point to a (after all, you are invoking the member function isitme() on object a through the pointer b).
Since a is what is being passed as an explicit argument, a is also what the reference cobj is bound to. Therefore, taking the address of cobj gives you the address of a. Which in turns mean, that the expression:
// Address of "a": "cobj" is bound to argument "a" in the function call
// vvvvv
&cobj == this
// ^^^^
// Address of "a": the function is called through a pointer to "a"
Evaluates to true.
The short answer is that b is a pointer to a -- they both refer to the same actual object, so when you compare those "two" objects' addresses, they compare equal.
There's something else that really needs to be pointed out, and although it's more comment than answer, it won't fit in a comment, so...
int CTest::isitme(CTest &cobj)
{
if(&cobj == this)
{
return true;
}
else
{
return false;
}
}
This is, quite honestly, pretty lousy code. Since it's really returning a bool, you should declare it to return a bool. It's also much better to directly return the result from the comparison. You should also do some reading about "const correctness". Taking those factors into account, your function ends up looking more like this:
bool CTest::isitme(CTest const &cobj) const {
return this == &cobj;
}
There are a couple of things going on here.
First, there is only one copy of CTest being allocated. To check this, you could put a print in the constructor:
class CTest {
public:
CTest() {
cout << "Constructor called";
}
...
};
If you then invoked your program, you'd see that the constructor was called only once.
When isitme is invoked, the this pointer is being compared to the address of the cobj parameter. Both are pointing to the same object, so they both contain the same memory address. Thus, the comparison passes.
The other thing to notice is that you are passing by reference. If you didn't pass by reference, then this would not work. For example, if you had the following code:
class CTest {
public:
...
bool isitme(CTest cobj) {
return this == &cobj;
}
};
Then the object would be passed by value. As a result, a copy of cobj is made. In fact, another constructor (the compiler provided default copy constructor) is called to make a new object which is a copy of the given one.
To prove this, override the default copy constructor to display a message.
class CTest {
public:
// Default constructor
CTest() {
cout << "Constructor called" << endl;
}
// Copy constructor
CTest(CTest& source) {
cout << "Copy constructor called" << endl;
}
// Comparison
bool isitme(CTest obj) {
return (this == &obj);
}
};
// Main program
int main (int argc, char* argv[]) {
...
CTest a;
CTest* b = &a;
cout << (b->isitme(a)) << endl;
...
}
Now if you run the program, you'd notice both constructors are called. The first time is during the constructor for a. The second time is when you pass a to the isitme method and it creates a copy.
When passed by value, the isitme check would fail because it is comparing the pointers (memory addresses) of two different objects.
int CTest::isitme(CTest &cobj)
{
// cobj is a reference, but still an object
CTest * pCobj = &cobj; //pCobj is now the pointer to the actual memory
//so it's the same as this pointer. Because you did before CTest *b = &a;
}
b is pointing a, then you are using a in
b->isitme(a)
the isitme() simply checks the object passed as parameter against this. In this case it is, so OK
Do I get a usual pointer as I pass a pointer to a reference of a variable or do i get a pointer to the reference? And what do i get as I pass a reference to a reference?
I am using the stack implementation of the standard library in a class, and i want to have some wrapper methods to prevent illegal access of the stack, but i am getting strange segfaults which i narrowed down to my getter-methods considering the stack.
Should those methods give back a clean reference/pointer to the original variable stored in the stack?
int& zwei() { return stack.top() };
and
int* eins() { return &stack.top() };
There is no such thing as a "pointer to a reference". References are aliases, and so taking the address of any of them will give a pointer to the same object:
int a;
int & b = a;
assert(&a == &b);
Your functions both return a valid result provided that the stack object is still alive in the scope of the function return.
std::stack<int> s;
int & foo() { return s.top(); } // OK, maybe
int * goo() { return &s.top(); } // ditto
int & boo() { std::stack<int> b; return b.top(); } // No! Dangling reference!
You should also check that the stack isn't empty, in which case top() is not valid.
(I should also council against calling a variable by the same name as a type, even though the type's name is std::stack.)