Pointer Vs. Reference

When to use references vs. pointers

Use reference wherever you can, pointers wherever you must.

Avoid pointers until you can't.

The reason is that pointers make things harder to follow/read, less safe and far more dangerous manipulations than any other constructs.

So the rule of thumb is to use pointers only if there is no other choice.

For example, returning a pointer to an object is a valid option when the function can return nullptr in some cases and it is assumed it will. That said, a better option would be to use something similar to std::optional (requires C++17; before that, there's boost::optional).

Another example is to use pointers to raw memory for specific memory manipulations. That should be hidden and localized in very narrow parts of the code, to help limit the dangerous parts of the whole code base.

In your example, there is no point in using a pointer as argument because:

  1. if you provide nullptr as the argument, you're going in undefined-behaviour-land;
  2. the reference attribute version doesn't allow (without easy to spot tricks) the problem with 1.
  3. the reference attribute version is simpler to understand for the user: you have to provide a valid object, not something that could be null.

If the behaviour of the function would have to work with or without a given object, then using a pointer as attribute suggests that you can pass nullptr as the argument and it is fine for the function. That's kind of a contract between the user and the implementation.

Pointer vs. Reference

My rule of thumb is:

Use pointers if you want to do pointer arithmetic with them (e.g. incrementing the pointer address to step through an array) or if you ever have to pass a NULL-pointer.

Use references otherwise.

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 is the difference between: Handle, Pointer and Reference

A handle is usually an opaque reference to an object. The type of the handle is unrelated to the element referenced. Consider for example a file descriptor returned by open() system call. The type is int but it represents an entry in the open files table. The actual data stored in the table is unrelated to the int that was returned by open() freeing the implementation from having to maintain compatibility (i.e. the actual table can be refactored transparently without affecting user code. Handles can only be used by functions in the same library interface, that can remap the handle back to the actual object.

A pointer is the combination of an address in memory and the type of the object that resides in that memory location. The value is the address, the type of the pointer tells the compiler what operations can be performed through that pointer, how to interpret the memory location. Pointers are transparent in that the object referenced has a concrete type that is present from the pointer. Note that in some cases a pointer can serve as a handle (a void* is fully opaque, a pointer to an empty interface is just as opaque).

References are aliases to an object. That is why you cannot have a reference to a reference: you can have multiple aliases for an object, but you cannot have an alias of an alias. As with pointers references are typed. In some circumstances, references can be implemented by the compiler as pointers that are automatically dereferenced on use, in some other cases the compiler can have references that have no actual storage. The important part is that they are aliases to an object, they must be initialized with an object and cannot be reseated to refer to a different object after they are initialized. Once they are initialized, all uses of the reference are uses of the real object.

What is the difference between a pointer and a reference variable in Java?

A reference is sort of like a pointer that you can't do arithmetic on... although it's more opaque. While the underlying bits may be an address in virtual memory, they don't have to be. They're just a way of getting to an object (or representing the null value). So while they're not exactly the same, if you're used to thinking of a pointer as "a way of identifying an object or navigating to it" (in some sense) then yes, those thoughts apply to references too.

Java doesn't have pointers as such (unlike, say, C# which has references and pointers - the latter being used in "unsafe" code).

Difference between pointer-to-pointer vs reference-to-pointer (C++)

The first example is that of a reference to a pointer, ie. a reference to a type IEnumWbemClassObject*:

HRESULT Query ( IN BSTR sQuery, OUT IEnumWbemClassObject* &pEnumerator );

Therefore if pEnumerator is declared as a IEnumWbemClassObject* (which I'm assuming it is), you don't need to explicitly pass the address of pEnumerator to the function or dereference the variable inside the function in order to change where pEnumerator points (which would otherwise be required with an argument of IEnumWbemClassObject**).

A reference to a pointer has the same behaviour as a reference to any other type, just think of the above example as being a "reference to a pointer" and not a "pointer to a reference." There's no such thing as a pointer to a reference.

difference between a pointer and reference parameter?

C++ references are intentionally not specified in the standard to be implemented using pointers. A reference is more like a "synonym" to a variable than a pointer to it. This semantics opens some possible optimizations for the compiler when it's possible to realize that a pointer would be an overkill in some situations.

A few more differences:

  • You can't assign NULL to a reference.
    This is a crucial difference and the
    main reason you'd prefer one over the
    other.
  • When you take the address of a
    pointer, you get the address of the
    pointer variable. When you take the
    address of a reference, you get the
    address of the variable being
    referred to.
  • You can't reassign a reference. Once it is initialized it points to the same object for its entire life.

What are the differences between a pointer and a reference in Rust?

Use references when you can, use pointers when you must. If you're not doing FFI or memory management beyond what the compiler can validate, you don't need to use pointers.

Both references and pointers exist in two variants. There are shared references & and mutable references &mut. There are const pointers *const and mut pointers *mut (which map to const and non-const pointers in C). However, the semantics of references is completely different from the semantics of pointers.

References are generic over a type and over a lifetime. Shared references are written &'a T in long form (where 'a and T are parameters). The lifetime parameter can be omitted in many situations. The lifetime parameter is used by the compiler to ensure that a reference doesn't live longer than the borrow is valid for.

Pointers have no lifetime parameter. Therefore, the compiler cannot check that a particular pointer is valid to use. That's why dereferencing a pointer is considered unsafe.

When you create a shared reference to an object, that freezes the object (i.e. the object becomes immutable while the shared reference exists), unless the object uses some form of interior mutability (e.g. using Cell, RefCell, Mutex or RwLock). However, when you have a const pointer to an object, that object may still change while the pointer is alive.

When you have a mutable reference to an object, you are guaranteed to have exclusive access to that object through this reference. Any other way to access the object is either disabled temporarily or impossible to achieve. For example:

let mut x = 0;
{
let y = &mut x;
let z = &mut x; // ERROR: x is already borrowed mutably
*y = 1; // OK
x = 2; // ERROR: x is borrowed
}
x = 3; // OK, y went out of scope

Mut pointers have no such guarantee.

A reference cannot be null (much like C++ references). A pointer can be null.

Pointers may contain any numerical value that could fit in a usize. Initializing a pointer is not unsafe; only dereferencing it is. On the other hand, producing an invalid reference is considered undefined behavior, even if you never dereference it.

If you have a *const T, you can freely cast it to a *const U or to a *mut T using as. You can't do that with references. However, you can cast a reference to a pointer using as, and you can "upgrade" a pointer to a reference by dereferencing the pointer (which, again, is unsafe) and then borrowing the place using & or &mut. For example:

use std::ffi::OsStr;
use std::path::Path;

pub fn os_str_to_path(s: &OsStr) -> &Path {
unsafe { &*(s as *const OsStr as *const Path) }
}

In C++, references are "automatically dereferenced pointers". In Rust, you often still need to dereference references explicitly. The exception is when you use the . operator: if the left side is a reference, the compiler will automatically dereference it (recursively if necessary!). Pointers, however, are not automatically dereferenced. This means that if you want to dereference and access a field or a method, you need to write (*pointer).field or (*pointer).method(). There is no -> operator in Rust.



Related Topics



Leave a reply



Submit