Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is operator-> "chained" for pointers? [duplicate]

Possible Duplicate:
Overloading operator ->

Hi,

I've seen that operator->() is chained (re-applied) after it is evaluated, for example:

struct Bar
{
  Bar() : m_str("Hello world!") {}
  const string* operator->() const { return &m_str; }
  string m_str;
};

struct Foo
{
  const Bar& operator->() const { return m_bar; }
  Bar m_bar;
};

int main()
{
  Foo f;
  cout << f->c_str() << endl;
  return 0;
}

works pretty fine, which requires three operator->() to be evaluated - Foo::operator->(), Bar::operator->() and regular pointer resolution.

But it wont work with pointers in the middle - if Foo::operator->() returns pointer to Bar instead of reference, it wont compile. Same happens with auto_ptr<auto_ptr<string>> for example.

Is it specific to non-overloaded operator->() so it is only applied once and does not cause chaining? Is it possible to make code below works without using (*ptr2)-> ...?

int main()
{
  string s = "Hello world";
  auto_ptr<string> ptr1(&s);
  auto_ptr<auto_ptr<string> > ptr2(&ptr1);
  cout << ptr1->c_str() << endl; // fine
  cout << ptr2->c_str() << endl; // breaks compilation
}

Thanks!

like image 951
nyrl Avatar asked Feb 07 '11 15:02

nyrl


2 Answers

C++98 standard §13.5.6/1 "Class member access":

An expression x->m is interpreted as (x.operator->())->m for a class object x of type T if T::operator-> exists and if the operator is selected at the best match function by the overload resolution mechanism (13.3).

What this means in practice is that when x is a pointer, you don’t get chaining; you then just get the built-in operator-> (i.e. x->m with x a pointer translates to (*x).m).

But when x is an object of class type T, then you can get the chaining effect. Because then the interpretation as (x.operator->())->m can be that (x.operator->()) itself is an object of some class, say class U. Whence the second -> can be resolved as U::operator->, and so on, if the result of that again is a class type object…

Like, in your case, Foo::operator-> produces (a reference to) an object of class Bar, which does define an operator->.

But when operator-> returns a pointer, as e.g. std::auto_ptr<T>::operator-> does, then it's just the built-in operator-> that's used.

In passing, the chaining can be used to practically prevent someone from using delete inappropriately. std::auto_ptr does not do that. And I’ve never seen it done.

But there was once a long discussion thread over in [comp.lang.c++.moderated] about how to prevent inadvertent delete of the raw pointer managed by a smart pointer, and this was one possibility that was discussed.

Cheers & hth.

like image 64
Cheers and hth. - Alf Avatar answered Nov 13 '22 05:11

Cheers and hth. - Alf


The reason your first example works is because you returned a reference instead of a pointer. That operator would normally be invalid except in the case that it is overloaded. Therefore, the compiler must execute the overloaded functions down the chain. However, in the case of auto_ptr you actually are returned a real pointer and the default operator -> is invoked for regular pointers.

Please see the Overloading operator -> question for more details.

like image 43
Judge Maygarden Avatar answered Nov 13 '22 06:11

Judge Maygarden