Compiling with GCC 4.8.1 (MinGW) with command: g++ -o test.exe test.cpp
test.cpp:
#include <iostream>
int a = 1, b = 2;
void F()
{
int &r = a;
std::cout << r;
r = b;
std::cout << r;
}
int main ( int, char** )
{
F();
F();
return 0;
}
The expected output is: 1212, but real is: 1222
It works as expected when r is defined as pointer.
void F()
{
int *r = &a;
std::cout << *r;
r = &b;
std::cout << *r;
}
Does someone have any idea where is "the key from the tent"?
In the example with a pointer:
r = &b;
This re-seats the pointer r to point to b. In the example with the reference:
r = b;
You probably think that this is analogous to the example with the pointer, but it is not. References are not re-seatable the way pointers are. Once they are initialized, they become aliases for the thing which they reference. So the line above is exactly equivalent to this:
a = b;
That is, it copies the value stored in b over to a.
The reference example is could be written like this:
void F()
{
std::cout << a;
a = b;
std::cout << a;
}
While the pointer example could be written like this:
void F()
{
std::cout << a;
std::cout << b;
}
Your "problem" is the following line:
int &r = a;
This will create a so called reference pointing to a. While references don't require additional logic when accessing them (i.e. dereferencing; compared to pointers), they still work the same way behind the scenes.
So once you hit the line
r = b;
You'll actually use the reference and update the value of a. In this case r never has it's own value. It will always point at a and essentially be an alias.
In your second example, this is different. The line
int *r = &a;
creates a pointer pointing at a and
r = &b;
will reassign that address, making the pointer now point at b.
In short, when you assign some other value (address) to a pointer, you change the pointer and it will point somewhere else. However, when assigning a new value to a reference, you're actually updating the inital value where it's referencing to, not the reference itself.
//global variables! remember that this will be like a state
//and will be freed on (data?BSS?stack?) only after end of program.
int a = 1, b = 2;
void F()
{
//You are referencing here,
//meaning, once you change the referee ( r )
//the reference will changed permanently.
//Permanently because you are referring to a global variable.
int &r = a;
std::cout << r;
//You have changed the value of ( r )
//forever!
r = b; //I think you are assuming the you have changed the reference address here?
std::cout << r;
}
void F()
{
//You have declared and initialized a pointer
//that points to global variable.
//w/c means you can also change its value forever!
int *r = &a;
std::cout << *r;
//You have changed the ( r ) address pointing to, not its value!
r = &b;
std::cout << *r;
}
Your code is absolutely fine and it's working according to your instruction.
Suppose a variable has 1000 address b variable 1004 address, now your first line is
int &r = a;
that means r has 1000 address and you did cout<< r //print 1
In second statement r = b that means 1000 address hold value of b means 2;
Now , your scenario has been changed 1000---> 2 and 1004--->2
and again you are calling F();
that's why compiler print twice 2 value. . There is a concept referencing in c++. Hope it
would be useful for u
Related
This has bothered me, I have just gotten back into c++ lately, and am well aware of references. Why does it seem there is no difference between b and c below. In other words, intuitively I would think c not being a ref variable would take a copy. It got me thinking when considering the problem of returning a reference to a local variable.
int a = 10;
int& func()
{
return a;
}
int &b = func();
int c = func(); // shouldn't this make a copy into c but c acts like a reference.
I would think c not being a ref variable would take a copy.
c is indeed a copy of a. Note that int c = func(); is copy initialization while int &b = func(); is reference initialization.
This means that if you make changes to c they will not be reflected on a. Demo
int a = 10;
int& func()
{
return a;
}
int &b = func(); //reference initialization
int c = func(); //copy initialization
int main()
{
c = 20;
std::cout << a<< " "<< b <<" "<< c <<std::endl; // 10 10 20
return 0;
}
Note also the emphasis on "initialization" instead of "assignment". These terms have different meaning in C++ unlike other languages(python for instance).
Thanks for the answers, makes sense now. This question started from "why can't I return a local variable reference to a variable if its a copy?" Well, I realized because its too late at that point - the stack is gone. I was thinking the copy could be made before the stack went away - wrong!
You can return to a reference but when you use it, segfault.
Return to a variable and, segfault immediately since it tries to copy.
int& func() // compile warning
{
int a = 10;
return a;
}
int &b = func(); // ok, but segfault if try to use b.
int c = func(); // segfault immediately
I have two data types, A and B and I have to store the A instance in B in order to refer the A instance in a B method. Both are instantiated in the main function, so the two variables would live for as long as the program is running.
I don't want to make copies, I want to use something like an old fashioned pointer but also I want to follow (and learn) the modern C++ best practices. So what is the most appropriate type to store the A instance in B? (and why?)
I thought that if I want to use a pointer, the best way with modern C++, is using smart pointers, but references seems easier and lighter, so what is the best practice to refer to a variable created in a scope (for example in the main function) and used in another scope (for example a method of a class that has a pointer to that variable), knowing that the scope where that variable is created lives for as long as the class exists (when the stack is deallocated, it will free both the variable and the object that has the variable reference)?
struct A {};
struct B {
A & a;
B(A & a) : a(a) {}
};
int main() {
A a{};
B b{a};
}
or
#include<memory>
struct A {};
struct B {
std::shared_ptr<A> a;
B(auto a) : a(a) {}
};
int main() {
B b{std::make_shared<A>()};
}
The program I'm making is essentially a bunch of test to learn SDL2, I published the repo here https://github.com/antcolag/prova-sdl, B is the App class and A is the EventHandler class instantiated inside the main function.
As #πάντα-ῥεῖ noticed in my particular case the only reasonable way is with smart pointer, because I'm trying to use std::thread and std::atomic, but in a most general case what is the best way to replace the old C style pointers, with a more modern approach, when a variable is allocated in the stack, used by some other object and then deallocated from the stack together with the object?
If i understood the problem, you want to move the instance to a different "owner", with A a; it is posible but it requires a memcpy() if the scope of the instance is deleted. The most easy solution is to contain it in a shared scope, that is bad because it can be a global scope, the next best thing is to pass the reference to the owner (the structure that contains the data). At the end this are cheap solutions if they are applied over and over, modern c++ has a lot of tools for memory control / flow; most of those are pointer based because the data pointer copy is trivial, note that only in combination with std::atomic or a similar lib is suitable for multithreading.
This example shows how a data pointer can be moved and used without any fancy c++, a small note on the pointer idea, in the example the pointer address is not changing as long as it is not deleted, any reference made will persist even if ref_objs order is changed, the data is "on the wild" and the pointer is a number.
#include <iostream>
struct Object {
int num = 69;
};
struct Container {
// Better to use std::vector but
// this shows better what it does
// Olso can be replaced with
// Object * ref_objs [n] if n is fixt
Object ** ref_objs;
uint32_t n_obj;
uint32_t n_obj_max;
void provision_for(uint32_t res_len){
// To initialize data is better to use
// use a method insted of the constructor;
// This alocates n spaces of obj pointers
ref_objs = new Object * [res_len];
n_obj_max = res_len;
n_obj = 0;
}
void clear_all(){
uint32_t i;
for (i=0; i < n_obj; i++){
delete ref_objs[i];
}
delete [] ref_objs;
n_obj = 0;
}
Object * add_obj(){
Object * ret = nullptr;
if (n_obj < n_obj_max){
ref_objs[n_obj] = new Object;
ret = ref_objs[n_obj];
n_obj++;
}
return ret;
}
void del_obj(uint32_t n){
if (n < n_obj - 1){
// keeps them alighned
ref_objs[n] = ref_objs[n_obj];
}
delete ref_objs[n_obj];
n_obj--;
}
int recive_obj(Object * ref){
int res = 1;
if (n_obj < n_obj_max){
ref_objs[n_obj] = ref;
n_obj++;
res = 0;
}
return res;
}
int transfer_to(Container * to, uint32_t item){
int res = 1;
if (to->recive_obj(ref_objs[item]) == 0){
if (item < n_obj - 1){
ref_objs[item] = ref_objs[n_obj - 1];
} else {
ref_objs[item] = nullptr;
}
n_obj --;
res = 0;
}
return res;
}
Object * at (uint32_t at){
return ref_objs[at];
}
Object & operator [](uint32_t at){
// [0] is added to asure the compiler that it
// is a instance and not an array
return ref_objs[at][0];
}
};
int main(void){
Container container_a;
Container container_b;
container_a.provision_for(10);
container_b.provision_for(15);
Object * x = container_a.add_obj();
Object * y = container_a.add_obj();
Object * z = container_b.add_obj();
std::cout << "container_a len -> " << container_a.n_obj << std::endl;
std::cout << "container_b len -> " << container_b.n_obj << std::endl;
y->num = 200;
container_a.transfer_to(&container_b, 0);
container_b[1].num = 400;
std::cout << "container_a obj[0].num -> " << container_a[0].num << std::endl;
std::cout << "container_b obj[0].num -> " << container_b[0].num << std::endl;
std::cout << "container_b obj[1].num -> " << container_b.ref_objs[1]->num << std::endl;
container_a.del_obj(0);
container_a.clear_all();
container_b.clear_all();
return 0;
}
(This example is template suitable, just change all Object with the typename and the instance will be Container<Object> container_a;)
In my understanding that might be wrong, declaring a pointer to local object is dangerous or probably has no purpose.
The following globally defined function Factory that returns a pointer to a local object has no purpose. Right after invoking Factory(), the returned address is pointing to a local object that has been destroyed.
Foo* Factory()
{
// It is wrong to return the address of a local object!
// It is only for illustration!
Foo local{ 100 };
return &local;
}
Invoking Print() produces a garbage value. This is understandable so far.
Now consider the second case with a local scope as follows.
int main()
{
Foo* p ;
{
Foo local{ 100 };
p = &local;
}
p->Print();// 100 is printed even though p is pointing to a local scoped object that has been destroyed.
return 0;
}
What I don't understand is why I can still invoke Print() on the pointed object that should have been destroyed. Any comments are welcome!
Complete Example
#include <iostream>
class Foo
{
private:
int _data;
public:
Foo(int data) :_data{ data }
{
std::cout << "Ctor: " << this << std::endl;
}
~Foo()
{
std::cout << "Dtor: " << this << std::endl;
}
void Print()
{
std::cout << "Data: " << _data << std::endl;
}
};
Foo* Factory()
{
// It is wrong to return the address of a local object!
// It is only for illustration!
Foo local{ 100 };
return &local;
}
int main_1()
{
Foo* p = Factory();
p->Print();// Garbage gets printed because p is pointing to a local object that has been destroyed.
return 0;
}
int main_2()
{
Foo* p ;
{
Foo local{ 100 };
p = &local;
}
p->Print();// 100 is printed even though p is pointing to a local scoped object that has been destroyed.
return 0;
}
Undefined behavior
First I want to give you a brief explanation of undefined behavior. If you want to you can read more here Undefined behavior.
Undefinded behavior renders the entire program meaningless if certain rules of the language are violated. The compiler can basicly decide what to do. But like mentioned on cppreference: Compilers are not required to diagnose undefined behavior (although many simple situations are diagnosed), and the compiled program is not required to do anything meaningful. So in short there are no restrictions on the behavior of the program.
Your case
Both examples invoke undefned behavior:
int main_2()
{
Foo* p ;
{
Foo local{ 100 };
p = &local;
}
p->Print();
return 0;
}
int main_1()
{
Foo* p = Factory();
p->Print();
return 0;
}
So like we learned undefinded behavior is undefinded. So anything can happen. In the second case your compiler was probably smart enough to notice the issue.Because the behavior is undefined your program could also crash or do other weird things.
This question already has answers here:
When I change a parameter inside a function, does it change for the caller, too?
(4 answers)
Closed 4 years ago.
I know call by pointers in which we pass address of variables.Something like this:
void swap(int *x, int *y)
{
int temp;
temp = *x; /* save the value at address x */
*x = *y; /* put y into x */
*y = temp; /* put x into y */
return;
}
swap(&a, &b);
And also call by reference,in both of these methods the changes made in the function are reflected in actual arguments' variable.
But why are actual parameters passed in this case of call not changed:
#include <iostream>
using namespace std;
void foo(int* c){
c=c+1;
}
int main()
{
int a=5;
int *c=&a;
cout<<&c<<endl; //0x7ffe1a74f3b0
foo(c);
cout<<*c<<endl;//5
cout<<&c<<endl;//0x7ffe1a74f3b0
}
Here c passed to foo() is address of a.So how this is call by value.
Here c should have printed garbage value according to me.Please explain what has happened here.
And also call by reference, in both of these methods the changes made in the function are reflected in actual arguments' variable.
There is an important difference, though: the changes are always made to whatever is referenced/pointed to, never to the reference/pointer itself (modifying a reference is impossible in general).
That is why assigning c a new value inside foo has no effect on c outside foo: the pointer passed to a function is copied.
If you need to modify the pointer, you need to add another level of dereference by passing a pointer reference or a pointer to a pointer.
Following on from comments, the variable c defined in function main is a different variable to the parameter c of function foo. If you want foo to be able to modify main's c, that is modify the address that c's pointer type holds, then you need to pass either a reference or pointer to c to the function instead.
Here is an example that shows the difference between passing c by value (as int *), or by reference (as int ** or int *&). Don't be fooled by the fact that int * is a pointer type, that means that it can receive an int by reference or an int * by value. And since main's c is int * rather than int, main c is being passed by value.
Note the differences in how the functions are called (whether c needs the address operator & in the function call) and the outcome of each function.
#include <iostream>
using namespace std;
void foo_int_ptr(int* c)
{
c=c+1;
}
void foo_int_ptr_ptr(int** c)
{
*c=*c+1;
}
void foo_int_ptr_ref(int*& c)
{
c=c+1;
}
int main()
{
int a=5;
int *c=&a;
cout << "&c=" << &c << ", c=" << c << ", *c=" << (c==&a ? std::to_string(*c) : std::string("INVALID PTR")) << endl;
foo_int_ptr(c);
cout << "&c=" << &c << ", c=" << c << ", *c=" << (c==&a ? std::to_string(*c) : std::string("INVALID PTR")) << endl;
foo_int_ptr_ptr(&c);
cout << "&c=" << &c << ", c=" << c << ", *c=" << (c==&a ? std::to_string(*c) : std::string("INVALID PTR")) << endl;
foo_int_ptr_ref(c);
cout << "&c=" << &c << ", c=" << c << ", *c=" << (c==&a ? std::to_string(*c) : std::string("INVALID PTR")) << endl;
}
Output:
&c=0x7e02d81808b8, c=0x7e02d81808ac, *c=5
&c=0x7e02d81808b8, c=0x7e02d81808ac, *c=5
&c=0x7e02d81808b8, c=0x7e02d81808b0, *c=INVALID PTR
&c=0x7e02d81808b8, c=0x7e02d81808b4, *c=INVALID PTR
there is a mistake in your thinking about this ..
int *c = &a;
this doesn't mean that c "contains" address of a, this means that c is a pointer TO the address of a. Passing a pointer to foo() will not do anything.
What is the best way to use Java-style references in C++? Will using shared_ptr for all classes and structs be the correct equivalent?
I highly recommend reading this answer for understanding C++ smart pointers.
Now, if by 'Java-style references' you mean you want to pass an object or struct into a method and that passed in object is not a copy of the object, but rather a reference to the object, then simply use pass by reference.
Ex:
void foo( int& ref, int val)
{
ref = ref + 1; // pass by reference
val = val + 1; // pass by value
}
...
int main()
{
int a = 10;
int b = 10;
foo(a, b);
// a is being passed by reference so foo directly modifies a
std::cout << "a = " << a << " b = " << b;
// output would be: a = 11 b = 10
}