Why reference is safer than pointer? [duplicate] - c++

This question already has answers here:
Why is a c++ reference considered safer than a pointer?
(9 answers)
Closed 5 years ago.
Hey I'm trying to understand what is the difference between pointer and reference in therm of safety to use, a lot of person say that reference are safer than pointer and it couldn't be null. But for the following code it show that reference could create run-time error but not the pointer :
class A {
public:
A(): mAi(0) {}
void ff() {std::cout << "This is A" << std::endl;}
int mAi;
};
class B {
public:
B() : mBi(0), mAp(NULL) {}
A* getA() const { return mAp; }
void ff(){std::cout << "This is B" << std::endl;}
int mBi;
A* mAp;
};
int main()
{
B* b = new B();
/// Reference part
A& rA = *b->getA();
rA.ff();
std::cout << rA.mAi << std::endl;
/// Pointer part
A* pA = b->getA();
if (NULL != pA)
{
pA->ff();
std::cout << pA->mAi << std::endl;
}
}
This code will crash for "reference part" but not for the "pointer part".
My questions are :
Why we always say that reference are safer than pointers if they could be invalid (as in the previous code) and we can't check for their invalidity?
There is any difference in terms of RAM or CPU consumption between using Pointer or Reference ? (Is it worth to refactor big code to use reference instead of pointer when we can then ?)

References cannot be NULL, that is correct. The reference part of your code however is crashing because you're explicitly trying to dereference a NULL pointer when you try to initialize the reference, not because the reference was ever null:
*b->getA(); // Equivalent to *((A*) NULL)
References can become dangling references though, if you did something like:
int* a = new int(5);
int& b = *a;
// Some time later
delete a;
int c = b + 2; // Ack! Dangling reference
A pointer wouldn't have saved you here, here's the equivalent code using a pointer:
int* a = new int(5);
int* b = a;
// Some time later
delete a;
if(b) { // b is still set to whatever memory a pointed to!
int c = *b + 2; // Ack! Pointer used after delete!
}
Pointers and references are unlikely to make any performance difference, they're probably similarly implemented under the hood depending on your compiler. References might be optimized out completely if the compiler can tell exactly what the reference is bound to.

Related

Different behaviour of unique_ptr vs raw pointer

I am struggling to understand the difference in behaviour of a raw pointer and a unique_ptr. I have class A with a variable x and class B with a pointer to an instance of A:
class A
{
public:
int x;
};
A::A(int y) : x(y)
{
}
class B
{
public:
B(A &);
A *p;
};
B::B(A &a)
{
p = &a;
}
This behaves as I would expect:
int main()
{
A a(2);
B b(a);
cout << a.x << " " << b.p->x << endl;
a.x = 4;
cout << a.x << " " << b.p->x << endl;
}
gives
2 2
4 4
Changing the raw pointer to a std::unique_ptr gives a different result:
class A
{
public:
int x;
};
A::A(int y) : x(y)
{
}
class B
{
public:
B(A &);
std::unique_ptr<A> p;
};
B::B(A &a)
{
p = std::make_unique<A>(a);
}
gives
2 2
4 2
Have I fundamentally misunderstood something about unique_ptrs?
make_unique creates a fresh object, one that that unique_pt has exclusive access to. So in the second example you have two objects, not one and when you set change the value of a.x in the first object it doesn't effect the other object held by the unique_ptr.
A unique pointer needs to own whatever it points to. Your code can be made to work - just substituting unique_ptr type and leaving everything else unchanged (no make_unique). But it will have undefined behavior, since you’ll create a unique pointer to an object that is owned elsewhere.
To compare apples to apples, the raw pointer code should read p=new A(a);. That’s what make_unique does.
Try reading the following expression from the smart pointer version:
std::make_unique<A>(a);
"make a unique A from a" (no mention of pointers!)
The result is a unique_ptr, but when reading the expression, read it as making (an object whose type is) the template parameter. The function parameters are parameters to the constructor. In this case, you are making an A object from an A object, which pulls in the copy constructor.
Once you understand that the smart pointer version is making a new A object (and your raw pointer version does not), your results should make sense.
The "unique" in "unique A" might be tricky to understand. Think of it as an object that no one else can lay claim to. It might be a copy of another object, but, taking the role of the unique_ptr, it is your copy, your responsibility to clean up after, and no one else's. Your preciousss, which you will not share (c.f. std::make_shared).
Note that a local variable (like the a in the main function) is the responsibility of the compiler, so it is ineligible to be the object to which a unique_ptr points (or any smart pointer, for that matter).

Does using the * operator on a pointer create a copy?

I've been curious about this for some time. Say we have the following cases for accessing a data member of a class stored in dynamically allocated memory:
class C {
public :
C() = default;
int a = 4;
}
int main () {
C * ptr = new C();
std::cout << "pointer->::" << ptr->a << std::endl;
std::cout << "dereference*().::" << (*ptr).a << std::endl;
}
I'm sure the pointer method is the preferred method, and my guess is that dereferencing the pointer provides a reference, at least in C++. But in C, where there are no references (and assuming appropriate modifications to convert the class to a struct etc), would dereferencing and accessing the member like this result in a temporary shallow copy? Is this something that the compiler optimizes out?
In both C and C++, *p (dereferencing) and p->m (member access through pointer) are "lvalue expressions". An lvalue "evaluates to the object identity". *p or p->m does not (by itself) create a copy, it refers to a variable that already exists.
Dereferencing a pointer does not create a copy neither for C neither for C++.
The result of a dereferencing operation is a lvalue that describe a pointed object.
But in any case the behaviour is the same for C and C++.

Limitations associated with returning a reference as opposed to a pointer [duplicate]

This question already has answers here:
What are the differences between a pointer variable and a reference variable?
(44 answers)
Closed 8 years ago.
What is the difference between returning by pointer and returning by reference? In both cases, the address is returned to the caller, am I right?
According to this little program - its obviously the same - it prints the value of an integer.
Are the any limitations concerning returning by reference rather than returning by pointer?
My teacher tells us - when you return by reference to a receiver, the receiver "borrows" the object. When you on the other hand return a pointer - you "transfer" the ownership of the object to the receiver.
#include <iostream>
using namespace std;
class A {
int x;
public:
A() : x(10) { }
void print() {
cout << "x = : " << x << endl;
}
};
class B {
int y;
public:
B() : y(30) { }
void print() {
cout << "x = : " << y << endl;
}
A& create() {
A* a = new A;
return *a;
}
};
Return by pointer, then these parts of the code I changed:
A* create() {
A* a = new A;
return a;
}
And in the main:
b.create()->print();
When you return a reference, you make an alias way to access to the object. It's like you are accessing the object directly.
By returning a pointer, you copy (not transfer) the address of the object. Then you need deferenece the pointer to access the object.
I think you can take a look at smart pointers such as std::unique_ptr and std::shared_ptr to understand transfering the ownership.
References are always treated as alias to original object, so no separate memory allocated to reference. Where as pointer has a separate memory address and store address of object.

create an instance for a pointer in other scopes

I have two methods to create an instance for a pointer.
But one of them will fail.
class A {
public:
int num;
};
void testPointer1(A* a){
a = new A();
a->num = 10;
}
A* testPointer2(){
A* a = new A();
a->num = 10;
return a;
}
void testPointer() {
A* a1 = NULL;
testPointer1(a1); // this one fails
//cout << a1->num << endl; // segmentation fault
A* a2 = NULL;
a2 = testPointer2();
cout << a2->num << endl;
}
why is testPointer1 wrong?
The syntax is valid, but it doesn't do what you want because testPointer1() is operating on a copy of the pointer, not the actual pointer itself. So when you assign the address to the newly allocated object, it gets assigned to the copy, not to the original a1 pointer.
Because of this, the address is lost and you get a memory leak. Also, since the original a1 pointer was never modified in the first place, you attempted to dereference a null pointer, which is a bad thing.
I'd say testPointer2() is the better way to do it, but if you want testPointer1() to work, try this:
void testPointer1(A*& a)
{
a = new A();
a->num = 10;
}
The parameter type indicates "a reference to a pointer to A." That way, instead of a copy of the pointer being passed, a reference to the original pointer will be passed. A C++ reference is an alias to another object. So whatever you do on the alias, it gets performed on the original object.
Extra notes:
Note that the parentheses in new A(); are actually significant and their presence or absence makes a difference.
Also note that you must manually delete all new'ed objects after you're done with them, or you will get a leak. Typically you would wrap the pointer in its own class and implement RAII or use a smart pointer such as Boost's smart pointers or auto_ptr, for proper memory management and exception safety.
If you're going to set the value of num on initialization, why not create a constructor?
class A
{
public:
A(int n) : num(n) {}
int GetNum() const { return num; }
private:
int num;
};
void testPointer1(A*& a)
{
a = new A(10);
}
A* testPointer2()
{
return new A(10);
}
// auto_ptr example, see link in second note above
std::auto_ptr<A> testPointer3()
{
return auto_ptr<A>(new A(10));
}
The testPointer1 functions works on a copy of the provided pointer : modifications to a in testPointer1 are not reflected to the caller.
It's exactly like in this simpler example :
void testInt1(int i)
{
i++;
}
void testInt()
{
int i = 0;
testInt1(i);
// i is still 0
}
If you want the change in testInt1 to be reflected to the caller, you have to pass either a pointer or reference to i (and not just the value of i). The same solution can be applied to your specific case, though one could argue that pointers to pointer and references to pointer are not really a best practice.
Is this homework ?
This seems to be obvious:
formal parameters are saved on the stack & restored after method/function call.
then whatever f(type x), manipulating x inside the function/method won't change it's value outside of the function.
even if type is a pointer type.
the only way to make x change inside a function is to tell it is modifiable through references or pointer to type.
in your case :
A* a1 =NULL
call to your method won't change value of a1 outside of testPointer1
so a1 will still be NULL after the call.

What would be the purpose of using the reference and dereference operators immediately in sequence "&*B"?

I have seen this in our code a couple times and it immediately makes me suspicious. But since I don't know the original intent I am hesitant to remove it.
//requires double indirection which I won't go into
FooClass::FooFunction(void ** param)
{
//do something
}
SomeClass * A = new SomeClass();
SomeClass **B = &A;
FooFunction( reinterpret_cast<void**>(&*B) ); // what is happening here?
The "&*B" part is the part in question? Feel free to integrate explanation of the reinterpret cast but I am pretty familiar with cast techniques.
I've done similar things with iterators - dereference the iterator to get a reference, and then do the "&" operator to get a pointer.
I don't see why it would be doing anything here though. If the type to the right of "&*" is a pointer type it does nothing.
I can see only one reason for this: B has overloaded operator*() to return an X, but whoever wrote the code needed an X*. (Note that in your code, X is A*.) The typical case for this is smart pointers and iterators.
If the above isn't the case, maybe the code was written to be generic enough to deal with smart pointers/iterators. Or it used to use smart pointers and whoever changed it didn't bother changing &*, too? Have you poked through its history to see when this was introduced and what the code looked then?
Consider the following sample;
class A {
public:
int f() { return 55; }
};
class B {
public:
B( A* a ) : a(a) {}
A*& operator*() { return a; }
A* a;
};
int main () {
A* a = new A();
B b = a;
// &* calls operator*, then gets address of A
void** x = reinterpret_cast<void**>(&*b);
cout << reinterpret_cast<A*>( *x )->f() << endl; // prints 55
void** x2 = reinterpret_cast<void**>( b ); // compile error
}
Your last edit of question leads to:
A* a = new A();
A** b = &a;
void** x = reinterpret_cast<void**>(&*b); // now this is equal to the following
void** x2 = reinterpret_cast<void**>( b ); // so using &* make no sense