7.3. Pointers to objects¶
As we have previously discussed, pointers can point to anything. We create pointers to objects much like any other type.
Raw pointers where we have to manage the memory ourselves:
int* p = new int{5};
dog* d = new dog{"Fido"};
And smart pointers that manage the memory for us:
auto p = std::unique_ptr<int>(new int{5});
auto d = std::unique_ptr<dog>(new dog{"Fido"});
In both cases, the initialization essentially identical.
Given a simple POD for a dog:
struct dog {
std::string name;
double age;
};
Access to members of any objects created uses the member access operator
operator .
:
// create a dog with initial values
dog buddy = {"Andy", 12.6};
// use member access operator to get values
std::cout << "My dog's name and age is: "
<< buddy.name << " and "
<< buddy.age << ".\n";
When you need to access members through a pointer,
the operator precedence rules for pointer dereference
and member access are a common source of error.
When buddy
is a pointer:
auto buddy = std::unique_ptr<dog>(new dog{"Andy", 12.6});
It seems that if buddy.name
works when not a pointer, then
given a pointer to a buddy
, that *buddy.name
should work, but it does not.
The member access operator has higher precedence than
the dereference operator.
The code *buddy.name
is equivalent to *(buddy.name)
.
This is almost always a bug.
In this case, name
is not a pointer type and cannot be dereferenced.
Explicit use of parentheses is one way to fix this problem:
(*buddy).name
This works, but the syntax is ugly.
For this reason, the operator ->
is used to
access members of a pointer to an object.
The code buddy->name
is easier to read than (*buddy).name
.
Putting it all together:
The last version is the most commonly used because it is less error prone and easier to read.
More to Explore
From cppreference.com