Reputation: 71
Passing an int
to an uninitialized pointer cannot work. But passing a reference to an uninitialized pointer can work.
What's the mechanism behind this?
int a = 1;
int &r = a;
cout << &a << " " << &r << endl; // 0x61ff10 0x61ff10
// can work
int *p1;
*p1 = r;
cout << p1 << endl; // 0x61ff60
// cannot work
int *p2;
*p2 = a;
return 0;
The code below is how I tested these strange concepts page 400 of cpp primer plus.
const free_throws & clone(free_throws & ft)
{
free_throws * pt;
*pt = ft; // copy info
return *pt; // return reference to copy
}
P.S.: I tried changing the value of a
and cout << *p1
always outputs the correct value:
int a = 3;
int &r = a;
cout << &a << " " << &r << endl;
// can work
int *p1;
*p1 = r;
cout << p1 << endl;
cout << *p1; // always the right value
Upvotes: 2
Views: 171
Reputation: 470
It is an undefined behavior in both cases, as *p1
and *p2
are uninitialized.
Check the instructions generated:
int a = 1;
Variable a
is stored and initialized in rbp-28
:
mov DWORD PTR [rbp-28], 1
int &r = a;
Then, alias r
is stored in rbp-8
, which is initialized reading &a
using lea
instruction:
lea rax, [rbp-28]
mov QWORD PTR [rbp-8], rax
int *p1; *p1 = r;
Pointer *p1
is stored in rbp-16
. The last mov
assigns *p1 = a
without initializing p1
to any value:
mov rax, QWORD PTR [rbp-8] # rax = address of r
mov edx, DWORD PTR [rax] # edx = value of a (deferences r)
mov rax, QWORD PTR [rbp-16] # rax = address of p1
mov DWORD PTR [rax], edx # rax = p1, [rax] = *p1, edx = a
int *p2; *p2 = a;
Pointer *p2
is stored in rbp-24
. As with p1
, p2
is assigned a value without pointing first to any valid address:
mov edx, DWORD PTR [rbp-28] # edx = value a
mov rax, QWORD PTR [rbp-24] # rax = address of p2
mov DWORD PTR [rax], edx # rax = p2, [rax] = *p2, edx = a
Upvotes: 0
Reputation: 40842
This Code from C++ Primer Plus (You shoudln't confuse "C++ Primer" a recommended book with "C++ Primer Plus") is not valid:
const free_throws & clone(free_throws & ft)
{
free_throws * pt;
*pt = ft; // copy info
return *pt; // return reference to copy
}
The text in the book above the shown code says:
A second method is to use
new
to create new storage. You’ve already seen examples in whichnew
creates space for a string and the function returns a pointer to that space. Here’s how you could do something similar with a reference
So the code meant to look like that (in an early revision of the book the new
was there):
const free_throws & clone(free_throws & ft)
{
free_throws * pt = new free_throws();
*pt = ft; // copy info
return *pt; // return reference to copy
}
If new
is missing then it is undefined behavior.
After the code the book also mentions that:
This makes jolly a reference to the new structure. There is a problem with this approach: You should use
delete
to free memory allocated bynew
when the memory is no longer needed.
So even with the new
it is a really bad code style.
i tried to change the value of a and
cout << *p1
can always output the correct value
int *p1; *p1 = r;
is undefined behavior, the compiler could make wrong assumptions about the code due to that, resulting in the compiler or optimizer create an unexpected/unpredictable machine code.
But what will most likely happen in practice for the shown code is: You don't initialize int *p1;
so p1
holds an undetermined value, this means it points to an arbitrary location in memory. If you are lucky it points to a valid memory address of currently not used memory. With *p1 = r;
you write to the memory at that memory address, if you are lucky nothing important is at that address so nothing bad happens, but you still write at a "random" position in memory. So you might get the correct result, but your code is still not valid.
But that's just one possible outcome that could happen.
Upvotes: 4
Reputation: 162
int a = 1;
int &r = a; // alias pointers reference above
cout << &a << " " << &r << endl; // 0x61ff10 0x61ff10 (Both address are same)
// It will also not work because you are not initializing p1
int *p1;
*p1 = r;
cout << p1 << endl; // Segmentation Fault
// Same but working code
int *p1 = &r;
cout << p1 << endl; // 0x61ff60
// cannot work (Because you have not initialized p2)
int *p2;
*p2 = a;
// Initialize p2 with a directly
int *p2 = &a;
cout << p2 << endl; // This time same address as of a
// or
int *p2 = new int;
*p2 = a;
cout << p2 << endl; // This time different address but same value of a
Upvotes: -2
Reputation: 75678
int a = 1;
int &r = a;
cout << &a << " " << &r << endl;
This is ok as every variable is initialized.
int *p1;
*p1 = r;
cout << p1 << endl;
This is incorrect because p1
is uninitialized. Accessing it (i.e. *p1
in your example) causes the program to have Undefined Behavior. Undefined behavior means anything can happen: the program can segfault, it can appear to work, it can print gibberish, really anything.
int *p2;
*p2 = a;
Same as previous. Access of uninitialized variable resulting in Undefined Behavior.
free_throws * pt;
*pt = ft;
Same as previous. Access of uninitialized variable resulting in Undefined Behavior.
Upvotes: 0