'In C++ why is it when I reassign a reference variable to a different reference variable it creates a copy of that variable instead?
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?
Solution 1:[1]
When you wrote:
conf.set_foo(b);
The following things happen:
Member function
set_foois called on the objectconf.Moreover, the reference parameter named
foo_is bound the the argument namedb. That is,bis 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 parameterfoo_to the object referred to by the data memberfoo(which is nothing butahere). You can confirm this by addingstd::cout<<a;after the call toset_fooas 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.
Solution 2:[2]
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;
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | fabian |
