class member access operator (->) overloading

A

Arkaitz Jimenez

For what I've seen around the operator-> is normally overloaded to
return the inner pointer in the case of a SmartPointer template.
However I was wondering if there is any way of having control after
the access was done, you can always execute code before returning the
pointer but obviously you can't after return.
So, is there anyway to get control before and after operator-> has its
effect?

Thanks

Arkaitz
 
V

Victor Bazarov

Arkaitz said:
For what I've seen around the operator-> is normally overloaded to
return the inner pointer in the case of a SmartPointer template.
However I was wondering if there is any way of having control after
the access was done, you can always execute code before returning the
pointer but obviously you can't after return.
So, is there anyway to get control before and after operator-> has its
effect?

If I understand correctly what you're after, then no. The overloaded
operator-> returns something (usually a pointer) for which another
operator-> will subsequently be applied. And that's until it's mapped
to the intrinsic operator-> for a pointer to a class object or a pointer
to a non-class object for a pseudo-destructor call.

#include <iostream>
#include <ostream>

using std::cout;

template<class T>
class AuxHasArrow
{
T* t;
public:
AuxHasArrow(T* t) : t(t) {}

T* operator->() { std::cout << "In Aux\n"; return t; }
};

template<class T>
class HasArrow
{
T* t;
public:
HasArrow(T* t) : t(t) {}
AuxHasArrow<T> operator->()
{ std::cout << "In HasArrow\n"; return AuxHasArrow<T>(t); }
};

struct A {
int a;
};

int main()
{
A a = { 42 };
HasArrow<A> ha(&a);

cout << ha->a << "after all\n";
}

See, there is nothing you can squeeze in your class to capture the
control after the operator-> is applied to the address of the 'a' object
(to extract that 42 for output).

V
 
V

Victor Bazarov

Stuart said:
What sort of control are you after? If you just want to execute some
code after the return, I guess you could always just return an instance
of another class with an overloaded operator->, which itself executes
some code and returns the actual pointer. That code would then be
executing after the original return.

I believe Arkaitz would like to have some code executed after the
intrinsic operator-> is applied to the [actual] pointer (that the op->
returns). I don't think this is possible from within the same class.
> But I'm not sure I understand the
motivation for doing this in the first place...

V
 
A

Arkaitz Jimenez

If I understand correctly what you're after, then no.  The overloaded
operator-> returns something (usually a pointer) for which another
operator-> will subsequently be applied.  And that's until it's mapped
to the intrinsic operator-> for a pointer to a class object or a pointer
to a non-class object for a pseudo-destructor call.

....
....
See, there is nothing you can squeeze in your class to capture the
control after the operator-> is applied to the address of the 'a' object
(to extract that 42 for output).

V

Well, that was my idea, that it couldn't be done, at least the way I
wanted to.

Thanks

Arkaitz
 
A

Arkaitz Jimenez

What sort of control are you after? If you just want to execute some
code after the return, I guess you could always just return an instance
of another class with an overloaded operator->, which itself executes
some code and returns the actual pointer. That code would then be
executing after the original return. But I'm not sure I understand the
motivation for doing this in the first place...

Regards,
Stu

Well, from what I know it's not possible, but just wondering if any
other trick was available.

The idea would be for example to wrap and mutexprotect one object
before and after a member is accessed or a method is executed.

Wraped<myobject> wrapobj;
wrapobj->whatever();
--------------------------
template operator -> would do:

mutex_lock(objolock);
wrapobj->called_method();
mutex_unlock(objlock);

Clearly there is no way of doing that with operator overloading, that
I know at least, but wanted to ask.


Thanks

Arkaitz
 
S

SG

For what I've seen around the operator-> is normally overloaded to
return the inner pointer in the case of a SmartPointer template.
However I was wondering if there is any way of having control after
the access was done, you can always execute code before returning the
pointer but obviously you can't after return.
So, is there anyway to get control before and after operator-> has its
effect?

Something like this?


struct do_nothing { void pre(){}; void post(){} };

template<typename T, typename U = T*,
typename prepost_func = do_nothing>
class ptrproxy
{
T* ptr;
public:
explicit ptrproxy(T* p) : ptr(p)
{ prepost_func().pre(); }

~ptrproxy()
{ prepost_func().post(); }

U operator->() const {return U(ptr);}
};

template<typename T, typename PrePost>
struct funky_pointer_metaf {
typedef ptrproxy<T,ptrproxy<T,T*,PrePost> > type;
};

#include <iostream>

struct S {
void blah()
{ std::cout << " --- S::blah ---\n"; }
};

struct my_prepost {
void pre() { std::cout << "prior access\n"; }
void post() { std::cout << "after access\n"; }
};

int main() {
S s;
typedef funky_pointer_metaf<S,my_prepost>::type funky_t;
funky_t p (&s);
p->blah();
p->blah();
}

which outputs:

prior access
--- S::blah ---
after access
prior access
--- S::blah ---
after access

?

Cheers!
SG
 
A

Arkaitz Jimenez

  struct do_nothing { void pre(){}; void post(){} };
  template<typename T, typename U = T*,
    typename prepost_func = do_nothing>
  class ptrproxy
  {
    T* ptr;
  public:
    explicit ptrproxy(T* p) : ptr(p)
    { prepost_func().pre(); }

    ~ptrproxy()
    { prepost_func().post(); }

    U operator->() const {return U(ptr);}
  };

  template<typename T, typename PrePost>
  struct funky_pointer_metaf {
    typedef ptrproxy<T,ptrproxy<T,T*,PrePost> > type;
  };

  #include <iostream>

  struct S {
    void blah()
    { std::cout << " --- S::blah ---\n"; }
  };

  struct my_prepost {
    void pre()  { std::cout << "prior access\n"; }
    void post() { std::cout << "after access\n"; }
  };

  int main() {
    S s;
    typedef funky_pointer_metaf<S,my_prepost>::type funky_t;
    funky_t p (&s);
    p->blah();
    p->blah();
  }

which outputs:

  prior access
   --- S::blah ---
  after access
  prior access
   --- S::blah ---
  after access

?

Cheers!
SG

Ok, It certainly does what I was looking for, lets see if I understand
it correctly.
You create a temporary sptr inside the original sptr return, that way
you can execute code using the temporary constructor and destructor
routines.
Smart, with this kind of method I'd only need to be careful to not use
throwable code inside the code intended to be executed after the call,
isn't it?

Thanks

Arkaitz
 
V

Victor Bazarov

SG said:
Something like this?


struct do_nothing { void pre(){}; void post(){} };

template<typename T, typename U = T*,
typename prepost_func = do_nothing>
class ptrproxy
{
T* ptr;
public:
explicit ptrproxy(T* p) : ptr(p)
{ prepost_func().pre(); }

~ptrproxy()
{ prepost_func().post(); }

U operator->() const {return U(ptr);}
};

template<typename T, typename PrePost>
struct funky_pointer_metaf {
typedef ptrproxy<T,ptrproxy<T,T*,PrePost> > type;
};

#include <iostream>

struct S {
void blah()
{ std::cout << " --- S::blah ---\n"; }
};

struct my_prepost {
void pre() { std::cout << "prior access\n"; }
void post() { std::cout << "after access\n"; }
};

int main() {
S s;
typedef funky_pointer_metaf<S,my_prepost>::type funky_t;
funky_t p (&s);
p->blah();
p->blah();
}

which outputs:

prior access
--- S::blah ---
after access
prior access
--- S::blah ---
after access

?

Nice!

It takes advantage of the extra indirection of the operator-> to return
the proxy temporary which will call the post-processing stuff in its
destructor that will be called *at the end of full expression*. I
thought about this, but hadn't find the *temporary* solution, for some
reason I was hung up on local objects, which get destroyed before the
final operator-> is used...

Thank you.

V
 
A

Alf P. Steinbach

* Victor Bazarov:
Nice!

It takes advantage of the extra indirection of the operator-> to return
the proxy temporary which will call the post-processing stuff in its
destructor that will be called *at the end of full expression*. I
thought about this, but hadn't find the *temporary* solution, for some
reason I was hung up on local objects, which get destroyed before the
final operator-> is used...

Thank you.

SG didn't provide a reference, but Bjarne once wrote a paper about exactly the
above technique.

So, let's also thank Bjarne Stroustrup.

Of course, some soul that-I-don't-recall-the-name-of at Microsoft should perhaps
also be thanked for the "COM call interceptor" which, even though it's not only
system specific but also technology specific, for what it does is more general.

And then also thanks to the folks at ParkPlace for the even more general C++
language extension or preprocessor or whatever it was that provides general call
interceptors for implemention of cross-code concerns (like e.g. logging); they
also should be thanked for the Smalltalk project when they were at Xerox PARC.

Argh, I cannot remember the name for that last technique!


Cheers,

- Alf
 
S

SG

SG didn't provide a reference

Right. I can't take credit for that (except for the attempt to use
exactly one class template instead of two with overloaded operator->()
to shorten the example). But I have no reference handy. I think I saw
it on someone's blog where the author used it for locking a mutex. I
probably wouldn't use it for locking, though.
but Bjarne once wrote a paper about exactly the
above technique.

So, let's also thank Bjarne Stroustrup.

Is it publicly available?

Cheers!
SG
 
A

Arkaitz Jimenez

Well, off the top of my head, return a proxy object whose constructor
locks the mutex and whose destructor unlocks it. In addition, the proxy
object should have an operator-> that returns a pointer to the actual
object.

But be careful: this is rarely the right approach for robust
multi-threaded applications. If you've determined that it's what you
need, fine; but if it's more a "wouldn't it be nice to be able to do
this" thing, then you might want to think about it some more. Usually
what's needed is locking higher up: lock, read some data from one
object, store the data in another object, unlock. In that sequence,
individual locks on the read and the write are pointless.

--
   Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of
"The Standard C++ Library Extensions: a Tutorial and Reference"
(www.petebecker.com/tr1book)

Yeah, I know its not a good practice for multithreading, it was just
an example actually.
The implementation you suggest is coded in this same thread by SG and
it works perfectly.

Thanks

Arkaitz
 
A

Alf P. Steinbach

* SG:
Right. I can't take credit for that (except for the attempt to use
exactly one class template instead of two with overloaded operator->()
to shorten the example). But I have no reference handy. I think I saw
it on someone's blog where the author used it for locking a mutex. I
probably wouldn't use it for locking, though.


Is it publicly available?

Bjarne Stroustrup: Generalizing Overloading for C++. Overload, Issue 25, April
1, 1998. Also, Chinese Translation. Programmer Magazine, April 1, 2002.
<url: http://www.research.att.com/~bs/wrapper.pdf>

It references
Michael Tiemann: "Wrappers:" Solving the RPC problem in GNU C++. Proceedings of
the USENIX C++ Conference, Denver, CO. October 1988.

Don't know what the April 1 publication dates mean, though.


Cheers,

- Alf (Google master)
 
S

SG

* SG:

Bjarne Stroustrup: Generalizing Overloading for C++. Overload, Issue 25, April
1, 1998. Also, Chinese Translation. Programmer Magazine, April 1, 2002.
<url:http://www.research.att.com/~bs/wrapper.pdf>

You mean
B. Stroustrup: Wrapping C++ Member Function Calls. The C++ Report.
June 2000, Vol 12/No 6. Code used for efficiency comparisons.

Thanks for the link. :) I must have used the wrong keywords for the
search.

Cheers!
SG
 
B

Bart van Ingen Schenau

Arkaitz said:
Ok, It certainly does what I was looking for, lets see if I understand
it correctly.
You create a temporary sptr inside the original sptr return, that way
you can execute code using the temporary constructor and destructor
routines.

Yes, that is correct.
Smart, with this kind of method I'd only need to be careful to not use
throwable code inside the code intended to be executed after the call,
isn't it?

Yes. Like with any class, it is a bad idea to throw an exception from a
destructor.
Thanks

Arkaitz

Bart v Ingen Schenau
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top