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 .

+3


source to share


4 answers


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->

.



+4


source


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;   

      

0


source


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

.

0


source


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;

      

0


source







All Articles