Why would I need to play out the iterator with a smart pointer twice instead of using the -> () operator?
Suppose I have the following code:
#include <iostream>
#include <deque>
#include <memory>
struct Test
{
int test;
};
int main(int, char**)
{
std::deque<std::unique_ptr<Test>> deque;
deque.push_back(std::unique_ptr<Test>(new Test{10}));
auto start = deque.begin();
std::cout << start->test << std::endl; // <- compilation error
std::cout << (start.operator->())->operator->()->test << std::endl; // <- OK
}
Why is smart-pointer treated as if it were a normal pointer object, although it is not (as I understand it)? From what I know, operator->()
must repeat until it reaches T*
.
Here are some related questions about how arrow overloading works and what we need to dereference twice instead of an arrow .
For an iterator, the it
expression is it->m
equivalent (*i).m
, technically it means that the iterator operator->
returns a raw pointer to the contained object. In your case, that means it returns a raw pointer to unique_ptr
. For this, the final one is applied operator->
and you get a reference to the contained object. This is why the chaining doesn't happen operator->
.
The arrow operator is overloaded for unique_ptr . Since you have an iterator, you are casting unique_ptr
, not the object that belongs to it. Therefore, you need to cast it twice.
std::cout << (*start)->test << std::endl;
A smart pointer type std::unique_ptr
is implemented to store a pointer and behave like a C pointer, while iterators are also pointers.
So why do you need to cast twice? Just because you have a pointer to a pointer to Test
.
This is exactly the same as if you had a container with simple pointers:
std::deque<Test*> dq;
dq.push_back(new Test{10});
auto start = dq.begin();
std::cout << (*start)->test << std::endl;