4

Suppose I have a 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 would be regular pointer object, although it is not (as far, as I understand)? From what I know, operator->() should recur until it reaches T*.

Here are some related questions on how arrow overloading works and that we need to dereference twice instead of an arrow.

Community
  • 1
  • 1
sukhmel
  • 1,402
  • 16
  • 29
  • 3
    The reapplication talked about there only refers to when `operator->` returns a non-pointer. The iterator's `operator->` returns a pointer to the value which then needs to be dereferenced again. If it returned a reference to the value it would chain. BTW, I prefer `(*start)->test`. – Dark Falcon Oct 01 '14 at 15:29

4 Answers4

5

For an iterator it, the expression it->m is equivalent to (*i).m, technically it means that the iterator's operator-> returns a raw pointer to the contained object. In your case it means it returns a raw pointer to the unique_ptr. A final operator-> is applied to that and you end up with a reference to the contained object. This is why no further chaining of operator-> occurs.

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
  • 1
    this "equivalent" thing in case of iterators still seems a little odd to me, sadly. But this explanation seems to fit well, thanks. – sukhmel Oct 02 '14 at 11:05
0

The arrow operator is overloaded for unique_ptr. Because you have an iterator, you are dereferencing to a unique_ptr, not the object owned by it. Therefore, you need to dereference twice.

std::cout << (*start)->test << std::endl;   
  • 1
    if `operator->` would return `unique_ptr` by reference, `operator->` would fall through to the object pointed, as this is how it works (recurs until pointer is met). So it does not really explains anything. – sukhmel Oct 02 '14 at 11:03
0

Smart pointer like std::unique_ptr are implemented to store a pointer and behave like a C pointer, while iterators also are pointers themselves.

So why you need to dereference twice? Simply because you have a pointer to pointer to Test.

nyarlathotep108
  • 5,275
  • 2
  • 26
  • 64
0

Its exactly the same as if you have a container of plain pointers:

std::deque<Test*> dq;
dq.push_back(new Test{10});
auto start = dq.begin();
std::cout << (*start)->test << std::endl;
quamrana
  • 37,849
  • 12
  • 53
  • 71