Why is a c++ reference considered safer than a pointer?
It's considered safer because a lot of people have "heard" that it's safer and then told others, who now have also "heard" that it's safer.
Not a single person who understands references will tell you that they're any safer than pointers, they have the same flaws and potential to become invalid.
e.g.
#include <vector>
int main(void)
{
std::vector<int> v;
v.resize(1);
int& r = v[0];
r = 5; // ok, reference is valid
v.resize(1000);
r = 6; // BOOM!;
return 0;
}
EDIT: Since there seems to be some confusion about whether a reference is an alias for an object or bound to a memory location, here's the paragraph from the standard (draft 3225, section [basic.life]
) which clearly states that a reference binds to storage and can outlive the object which existed when the reference was created:
If, after the lifetime of an object has ended and before the storage which the object occupied is reused or
released, a new object is created at the storage location which the original object occupied, a pointer that
pointed to the original object, a reference that referred to the original object, or the name of the original
object will automatically refer to the new object and, once the lifetime of the new object has started, can
be used to manipulate the new object, if:
- the storage for the new object exactly overlays the storage location which the original object occupied,
and- the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
- the type of the original object is not const-qualified, and, if a class type, does not contain any non-static
data member whose type is const-qualified or a reference type, and- the original object was a most derived object of type
T
and the new object is a most derived object of typeT
(that is, they are not base class subobjects).
Why is the argument of the copy constructor a reference rather than a pointer?
There are many reasons:
References cannot be NULL. OK, it's possible to create a NULL reference, but it's also possible to cast a
std::vector<int>*
into astd::vector<SomeType>*
. That doesn't mean such a cast has defined behavior. And neither does creating a NULL reference. Pointers have defined behavior when set to NULL; references do not. References are therefore always expected to refer to actual objects.Variables and temporaries cannot be implicitly converted into pointers to their types. For obvious reasons. We don't want pointers to temporaries running around, which is why the standard expressly forbids doing it (at least when the compiler can tell you are doing it). But we are allowed to have references to them; these are implicitly created.
Because of point number 2, using pointers rather than references would require every copy operation to use the address-of operator (&). Oh wait, the C++ committee foolishly allowed that to be overloaded. So any copy operation would need to actually use
std::addressof
, a C++11 feature, to get the address. So every copy would need to look likeType t{std::addressof(v)};
Or you could just use references.
What is the difference between a C# Reference and a Pointer?
C# references can, and will be relocated by garbage collector but normal pointers are static. This is why we use fixed
keyword when acquiring a pointer to an array element, to prevent it from getting moved.
EDIT: Conceptually, yes. They are more or less the same.
What's the low-level difference between a pointer an a reference?
Theoretically, they could be implemented in different ways.
In practice, every compiler I've seen compiles pointers and references to the same machine code. The distinction is entirely at the language level.
But, like cdiggins says, you shouldn't depend on that generalization until you've verified it's true for your compiler and platform.
Is the practice of returning a C++ reference variable evil?
In general, returning a reference is perfectly normal and happens all the time.
If you mean:
int& getInt() {
int i;
return i; // DON'T DO THIS.
}
That is all sorts of evil. The stack-allocated i
will go away and you are referring to nothing. This is also evil:
int& getInt() {
int* i = new int;
return *i; // DON'T DO THIS.
}
Because now the client has to eventually do the strange:
int& myInt = getInt(); // note the &, we cannot lose this reference!
delete &myInt; // must delete...totally weird and evil
int oops = getInt();
delete &oops; // undefined behavior, we're wrongly deleting a copy, not the original
Note that rvalue references are still just references, so all the evil applications remain the same.
If you want to allocate something that lives beyond the scope of the function, use a smart pointer (or in general, a container):
std::unique_ptr<int> getInt() {
return std::make_unique<int>(0);
}
And now the client stores a smart pointer:
std::unique_ptr<int> x = getInt();
References are also okay for accessing things where you know the lifetime is being kept open on a higher-level, e.g.:
struct immutableint {
immutableint(int i) : i_(i) {}
const int& get() const { return i_; }
private:
int i_;
};
Here we know it's okay to return a reference to i_
because whatever is calling us manages the lifetime of the class instance, so i_
will live at least that long.
And of course, there's nothing wrong with just:
int getInt() {
return 0;
}
If the lifetime should be left up to the caller, and you're just computing the value.
Summary: it's okay to return a reference if the lifetime of the object won't end after the call.
Double pointer vs pass by reference pointer
"Why using reference to pointer instead of pointer to pointer"? You will get the same answer as if asking "why using pointer instead of reference" for any other kind of variable...
Basically:
references (to pointer or any other variable) are smart because there should always be an object behind
pointers (to pointer or any other variable) are smart because they could possibly be
NULL
(optional)references (to pointer or any other variable) are not available in C
references (to pointer or any other variable) are smart because they can be used as objects (no need to dereference like pointers, easier syntax, rading)
etc...
There are many posts answering this question already:
What are the differences between a pointer variable and a reference variable in C++?
Are there benefits of passing by pointer over passing by reference in C++?
When Exactly Is A C#/.NET REF Parameter dereferenced? (Looking At Thread Safety)
I wrote this little sample program to demonstrate what I mean about ref
being dereferenced every time it is used. I hope this helps.
As far as thread safety is concerned, when ref
gets dereferenced has little effect. Your code needs to ensure that no two threads are modifying the value at the same time, and that no threads are reading the value until the writing threads have completed.
Your new code is much improved. But remember, it is the locks that are making your code thread safe, not when ref
is dereferenced.
class Program
{
static void Main(string[] args)
{
var a = new Test { Name = "First" };
ref Test b = ref a;
ref Test c = ref a;
Console.WriteLine(b.Name); // dereferences b, prints "Hello World!"
Console.WriteLine(c.Name); // dereferences c, prints "Hello World!"
b = new Test { Name = "Goodbye :(" }; // change the target of ref b to a new object
// dereference c again, points to the new object
// prints "Goodbye :("
Console.Write(c.Name);
}
}
public class Test
{
public string Name { get; set; }
}
Why is it allowed to cast a pointer to a reference?
Well, that's the purpose of reinterpret_cast
! As the name suggests, the purpose of that cast is to reinterpret a memory region as a value of another type. For this reason, using reinterpret_cast
you can always cast an lvalue of one type to a reference of another type.
This is described in 5.2.10/10 of the language specification. It also says there that reinterpret_cast<T&>(x)
is the same thing as *reinterpret_cast<T*>(&x)
.
The fact that you are casting a pointer in this case is totally and completely unimportant. No, the pointer does not get automatically dereferenced (taking into account the *reinterpret_cast<T*>(&x)
interpretation, one might even say that the opposite is true: the address of that pointer is automatically taken). The pointer in this case serves as just "some variable that occupies some region in memory". The type of that variable makes no difference whatsoever. It can be a double
, a pointer, an int
or any other lvalue. The variable is simply treated as memory region that you reinterpret as another type.
As for the C-style cast - it just gets interpreted as reinterpret_cast
in this context, so the above immediately applies to it.
In your second example you attached reference c
to the memory occupied by pointer variable pc
. When you did c = 'B'
, you forcefully wrote the value 'B'
into that memory, thus completely destroying the original pointer value (by overwriting one byte of that value). Now the destroyed pointer points to some unpredictable location. Later you tried to dereference that destroyed pointer. What happens in such case is a matter of pure luck. The program might crash, since the pointer is generally non-defererencable. Or you might get lucky and make your pointer to point to some unpredictable yet valid location. In that case you program will output something. No one knows what it will output and there's no meaning in it whatsoever.
One can rewrite your second program into an equivalent program without references
int main(){
char* pc = new char('A');
char* c = (char *) &pc;
std::cout << *pc << "\n";
*c = 'B';
std::cout << *pc << "\n";
}
From the practical point of view, on a little-endian platform your code would overwrite the least-significant byte of the pointer. Such a modification will not make the pointer to point too far away from its original location. So, the code is more likely to print something instead of crashing. On a big-endian platform your code would destroy the most-significant byte of the pointer, thus throwing it wildly to point to a totally different location, thus making your program more likely to crash.
Related Topics
What's the Best Hashing Algorithm to Use on a Stl String When Using Hash_Map
Delete Pointer to Multidimensional Array in Class Through Another Pointer - How
Why Simple Console App Runs But Dialog Based Does Not Run in Win Ce 6.0
Macros in the Middle of a Class or Function Declaration
Symbol Not Found When Using Template Defined in a Library
Why Do C++ Template Definitions Need to Be in the Header
Opencv Imshow Not Displaying Image in Osx
Cannot Open Output File, Permission Denied
How to Write and Read To/From a Qresource File in Qt 5
Sigkill While Allocating Memory in C++
Problems with C++ Set Container
Mixing Ifstream Getline and >>
Converting Integer into Array of Digits
How to Make My Program in Qt Continually Send a String to My Arduino