I a trying to store int by reference as data member of class.
I expected that is object get int by refernce than if I increase the reference from outside its increase the value inside the object.
class A
{
private :
int& x;
public:
A(int y) : x(y)
{
cout << "A's ctor x = " << x << endl;
}
void print()
{
cout << "x = " << x << endl;
}
};
int main()
{
int i = 8;
A a(i);
a.print();
++i;
a.print();
}
The output is :
A's ctor x = 8
x = 8
x = 8
Why x isnt 9?
The issue is that you're binding a temporary (the constructor parameter y) to a reference. The lifetime of the temporary is restricted to the constructor, but your reference lives on, becoming a "dangling" reference. This is what a reasonable compiler has to say about the matter:
crap13.cpp:10:18: warning: binding reference member 'x' to stack allocated parameter 'y' [-Wdangling-field]
A(int y) : x(y)
You can "fix" this by making the constructor parameter a reference:
A(int& y) : x(y)
but you must ensure that whatever is passed as argument to the constructor outlives the object being constructed.
The problem is that you are passing int by value in your constructor, you should pass it by reference:
A(int& y) : x(y)
{
cout << "A's ctor x = " << x << endl;
}
Related
struct configfs
{
int & foo;
configfs(int & foo_) : foo(foo_) {}
void set_foo(int & foo_)
{
foo = foo_;
}
};
int main() {
int a = 1;
configfs conf(a);
a = 3;
std::cout << conf.foo; // 3
std::cout << a; // 3
int b = 2;
conf.set_foo(b);
b = 9;
std::cout << conf.foo; // 2
std::cout << b; // 9
return 0;
}
When I initialize configfs with int a and then alter a in the main function it also alters configfs.foo . But when I reassign configfs.foo to a new reference and alter that reference in the main function, the behavior is different. Why? Is there a way so that when I run conf.set_foo(b) and then alter b in the main scope, it also alters conf.foo as well?
When you wrote:
conf.set_foo(b);
The following things happen:
Member function set_foo is called on the object conf.
Moreover, the reference parameter named foo_ is bound the the argument named b. That is, b is passed by reference.
Next, the statement foo = foo_; is encountered. This is an assigment statement and not an initialization. What this does is that it assigns the value referred to by the parameter foo_ to the object referred to by the data member foo(which is nothing but a here). You can confirm this by adding std::cout<<a; after the call to set_foo as shown below:
int b = 2;
conf.set_foo(b);
std::cout<<a<<std::endl; //prints 2
This is because operations on a reference are actually operations on the object to which the reference is bound. This means that when we assign to a reference, we are assigning to the object to which the reference
is bound. When we fetch the value of a reference, we are really fetching the value of the object to which the reference is bound.
Note: Once initialized, a reference remains bound to its initial object. There is no way to rebind a reference to refer to a different
object.
Refercences can only be "assigned" during initialization. They cannot be "retargeted" the way like pointers. After the initialization the memory the reference refers to remains fixed and any assignment using = results in the invokation of the assignment operator to the memory the reference refers to. That's the way it's specified in the C++ standard.
You could rewrite the example using a custom type with assignment operators printing the information about calls:
template<class T>
struct configfs
{
T& foo;
configfs(T& foo_) : foo(foo_) {}
void set_foo(T& foo_)
{
foo = foo_; // this uses the assignment operator assigning to the variable foo is an alias for
}
};
// Type wrapping the int and printing out the operations applied
struct TestWrapper
{
TestWrapper(int value)
: value(value)
{
std::cout << "TestWrapper::TestWrapper(" << value << ")\n";
}
TestWrapper(TestWrapper const& other)
: value(other.value)
{
std::cout << "TestWrapper::TestWrapper(TestWrapper{" << other.value << "})\n";
}
TestWrapper& operator=(TestWrapper const& other)
{
std::cout << "TestWrapper::operator=(TestWrapper{" << other.value << "})\n";
value = other.value;
return *this;
}
int value;
};
std::ostream& operator<<(std::ostream& s, TestWrapper const& val)
{
s << val.value;
return s;
}
int main() {
TestWrapper a = 1;
configfs<TestWrapper> conf(a);
a = 3;
std::cout << conf.foo << '\n'; // 3
std::cout << a << '\n'; // 3
TestWrapper b = 2;
conf.set_foo(b); // TestWrapper::operator=(TestWrapper{2})
b = 9;
std::cout << conf.foo << '\n'; // 2
std::cout << b << '\n'; // 9
return 0;
}
This question already has answers here:
What is a reference variable in C++?
(12 answers)
Closed 1 year ago.
class Pointer {
private:
int &x;
public:
Pointer(int &y) : x(y) {}
int getT() { return x; }
};
int main()
{
int w = 40;
Pointer test(w);
std::cout << &test <<' ' << &w;
}
What is the significance of the int &x declaration in the class definition? I understand that the int &y passed as a parameter for the constructor is the value passed by reference, but what about int &x as this type of declaration is showing me an error inside the main() function?
In the both cases in the constructor declaration
Pointer(int &y) : x(y) {}
and in the data member declaration
int &x;
there is declared a reference.
After calling the constructor
Pointer test(w);
the object test contains a reference to the object w passed by reference.
So for example you could write
int w = 40;
Pointer test(w);
std::cout << test.get() << '\n';
and the output will be
40
Now you can change the variable w as for example
w = 100;
and this statement
std::cout << test.get() << '\n';
will output
100
because it outputs a value of the same object stored in the object test by reference.
The reference x will be valid in the object test while the referenced object w is itself alive.
I need to understand why x(x + 1) happened only after I get out of the constructor.
class A
{
protected:
int x;
public:
A(int x = 5) : x(x + 1)
{
cout << "In A::A x=" << x << endl;
}
operator int() const { return x; }
};
void main()
{
A a1(10);
cout << a1 << endl ;
}
I was thinking I will get:
In A:: An x=11
11
But somehow I've got:
In A:: An x=10
11
You have two variables named x.
Inside the body of the constructor the argument variable will shadow the member variable. Whenever you use x inside the body of the constructor, it will be the argument, not the member.
To use the member variable you need to explicitly fetch it from the object, like this->x.
General tip: Don't use the same name for symbols in nested scopes. Besides solving this problem, it will also make the code easier to read and understand.
Your parameter is hiding the member variable of the same name - your definition is equivalent to
class A
{
protected:
int y;
public:
A(int x = 5) : y(x + 1)
{
cout << "In A::A x=" << x << endl;
}
operator int() const { return y; }
};
When a parameter has the same name as a member, you need to explicitly refer to the member with this->.
(The initialiser list follows its own rules.)
I have a basic understanding of this pointer in C++.While studying have come across the following code:
#include<iostream>
using namespace std;
class Test
{
private:
int x;
int y;
public:
//Test (int x = 0, int y = 0) { this->x = x; this->y = y; }
Test setX(int a) { x = a; return *this; }
Test setY(int b) { y = b; return *this; }
void print() { cout << "x = " << x << " y = " << y << endl; }
};
int main()
{
Test obj1;
obj1.setX(10).setY(20);
obj1.print();
return 0;
}
My issue is why the compiler deosn't report an error where I am returning a this pointer in SetX and SetY functions but haven't stated the return type as a pointer?
This comes because you're returning *this not this.
this is the pointer to a object of type Test. This means the this-variable basically holds the address where the object is stored. To access the object on which this points you use the *.
So you're returning the actual object on which you this Pointer points at.
EDIT
The problem why your code does not work in the way you want it to do is caused by the fact, that you're working on the stack.
Let's take a look at the addresses:
#include<iostream>
using namespace std;
class Test
{
private:
int x;
int y;
public:
//Test (int x = 0, int y = 0) { this->x = x; this->y = y; }
Test setX(int a) { x = a; return *this; }
Test setY(int b) {
y = b;
cout << this << endl; // >> 0x29ff18
return *this;
}
void print() { cout << "x = " << x << " y = " << y << endl; }
};
int main()
{
Test obj1;
cout << &obj1 << endl; // >> 0x29ff10
obj1 = obj1.setX(10).setY(20);
cout << &obj1 << endl; // >> 0x29ff10
//obj1.setY(20);
obj1.print();
return 0;
}
As you can see, the object where this points at is at a different address within you setY method compared to the main. This is because the object is copied to the stackframe of the setY method - so within setX and setY you're working with a copy of obj1
If you're doing obj1.setX(10).setY(20); you basically copy the object obj1 and use it within setX and the return object of setX is then used in setY. If you want to save the last copy, you have to reassign it to obj1.
Your solution to the problem works, but is grossly inefficient. The last paragraph describing what is happening is incorrect. setx is called with and uses obj1. sety is called with and uses copy of obj1. obj1 is then assigned copy of copy of obj1 returned by sety. The address doesn't change because obj1's storage is being overwritten, not replaced. Add a copy constructor and an assignment operator and you can watch what's really happening. The recommended solution is to use references to the same object throughout and chaining as per #πάνταῥεῖ 's answer below. – user4581301
My issue is why the compiler deosn't report an error where I am returning a this pointer in SetX and SetY functions but haven't stated the return type as a pointer?
It's completely valid syntax, so the compiler isn't supposed to return an error message. The problem is that you're using copies of this* with your return type.
To chain operations properly to operate on the original instance return a reference to this:
Test& setX(int a) { x = a; return *this; }
// ^
Test& setY(int b) { y = b; return *this; }
// ^
Otherwise you're returning an unrelated copy of your class.
Suppose that both the objects (of the same class) have been initialized already.
Now, you do:
Object2 = Object1;
In Java, what happens is that both Object1 and Object2 now point to the same memory location.
What happens in C++?
#include <iostream>
using namespace std;
class X {
public:
X() {
cout << "Default Constructor called\n";
i = 0;
}
X(int i) {
cout << "Parameterized Constructor called\n";
this->i = i;
}
X (const X& x) {
cout << "Copy Constructor called\n";
i = x.getI();
}
~X() {
cout << "Destructor called\n";
}
int getI() const {
return i;
}
private:
int i;
};
void main() {
cout << "\nLine-1\n\n";
X x1(1); // On Stack
cout << "\nLine-2\n\n";
X* x2 = new X(2); // On Heap
cout << "\nLine-3\n\n";
X x3(x1);
cout << "\nLine-4\n\n";
X* x4 = new X(x1);
cout << "\nLine-5\n\n";
X x5 = x1;
cout << "\nLine-6\n\n";
x5 = x3;
cout << "\nLine-7\n\n";
X x6 = *x2;
cout << "\nLine-8\n\n";
*x2 = *x4;
cout << "\nLine-9\n\n";
*x4 = x3;
cout << "\nLine-10\n\n";
}
As you can see, whenever I do createdObj1 = createdObj2, none of the constructors is invoked.
The function operator=() defines what happens. It can be defined as a member function, typically:
Object & Object::operator=(const Object &other);
If you do not provide one of these functions, a default implementation will be provided, which uses the operator=() function for each member variable.
Two major cases exist:
When performing an declaration with assignment, as in
X x = y;
it is usually (see the comment #T.C. made about explicit copy constructors) equivalent to
X x(y);
and thus will simply construct your new object in place. No assignment is done at all. This obviously creates a new object x which has automatic storage duration. (If I had written (static X x = y; it would have had static storage duration instead.)
The other case is
x = y;
where x is modified to equal y. This is done by calling X::operator=(X), whose default implementation will simply assign each member in turn. (A custom version can do whatever it wants.)