C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Calling member function using a smart pointer and a pointer

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Howard Gardner
Guest





PostPosted: Sun Jan 30, 2005 4:10 am    Post subject: Calling member function using a smart pointer and a pointer Reply with quote



/*
I'm trying to figure out how to call a class member function using a
pointer to the member function and either a real pointer to the class or
a smart pointer to the class. So far, I've been unable to find the
syntax that I need. I have hacked together a solution that I think I
could use, and that doesn't require that syntax, but the solution is
unlovely and I'd much prefer to find the syntax.

There is one significant constraint: I want to use operator ->() in the
smart pointer, because I intend to exploit the "temporary's lifetime
benefit." If I can't get to that benefit, then there's no reason for me
to write the code that requires this syntax in the first place.

I'd obviously like to avoid burdening either the class or the smart
pointer with any additional syntax if at all possible: the solution that
I hacked together manages to do this, at least as far as I've taken it.
If theres a clean solution that burdens the smart pointer--for instance,
writing operator ->*()--then that might be ok. Burdening the class just
won't do.

Lastly, the signature of the member function is not an issue. In the
context in which I want to make this call, that signature is known. In
other words, if you can show me how to make the sample code below work,
then I can handle the rest of the problem.

The missing syntax is--well--missing. I've commented out a couple of
things that won't do.

**

The "temporary's lifetime benefint" is the fact that operator ->() can
return something that is not really a pointer to the pointee, and which
has a really useful lifetime.

Alexandrescu mentions this in "Modern C++ Design, section 7.3", and
elaborates on its potential utility in multithreaded applications in
"Modern C++ Design, section 7.13.1".

Alexandrescu refers to Stroustrup's paper "Wrapping Calls to Member
Functions", which was published in C++ Report in June of 2000. This
paper appears to be available on the web at:

http://www.research.att.com/~bs/wrapper.pdf

Stroustrup also deals with the topic in "The C++ Programming Language,
section 11.10."

**

*/

#include <iostream>
using namespace std;

// Some random class that has a member function
struct example
{
void mem_func() const
{cout << "example::mem_func" << endl;}
};

// A deliberately minimalist "smart pointer"
template < typename xPointee >
struct ptr
{
typedef ptr tSelf;
typedef xPointee tPointee;
typedef xPointee * tPointer;

ptr(const tSelf & fThat)
:cPointer(fTHat.cPointer)
{cout << "ptr::copy" << endl;}

explicit
ptr(tPointer fPointer)
:cPointer(fPointer)
{cout << "ptr::conversion" << endl;}

~ptr()
{cout << "ptr::destructor" << endl;}

tPointee operator *()
{cout << "ptr::operator *()" << endl; return *cPointer;}

tPointer operator ->()
{cout << "ptr::operator ->()" << endl; return cPointer;}

tPointer cPointer;
};

// An attempt to call a member mem_function through either a smart
// pointer or a pointer
template < typename xPtrLike, typename xPtrMemFunc >
void
call(xPtrLike fPtrLike, xPtrMemFunc fPtrMemFunc)
{
cout << "call" << endl;

// Next line works fine, but I lose the "temporary lifetime benefit"
// ((*fPtrLike).*fPtrMemFunc)();

// Next line works for a real pointer, but not ptr< >
// (fPtrLike->*fPtrMemFunc)();
}

int main()
{
example fExample;
call(&fExample, &example::mem_func);
cout << endl;
call(ptr< example >(&fExample), &example::mem_func);
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Ivan Vecerina
Guest





PostPosted: Sun Jan 30, 2005 10:57 am    Post subject: Re: Calling member function using a smart pointer and a poin Reply with quote



"Howard Gardner" <usenet (AT) hgardner (DOT) com> wrote

Hi,
Quote:
I'm trying to figure out how to call a class member function using a
pointer to the member function and either a real pointer to the class or
a smart pointer to the class. So far, I've been unable to find the
syntax that I need. I have hacked together a solution that I think I
could use, and that doesn't require that syntax, but the solution is
unlovely and I'd much prefer to find the syntax.

There is one significant constraint: I want to use operator ->() in the
smart pointer, because I intend to exploit the "temporary's lifetime
benefit." If I can't get to that benefit, then there's no reason for me
to write the code that requires this syntax in the first place.

I'd obviously like to avoid burdening either the class or the smart
pointer with any additional syntax if at all possible: the solution that
I hacked together manages to do this, at least as far as I've taken it.
If theres a clean solution that burdens the smart pointer--for instance,
writing operator ->*()--then that might be ok. Burdening the class just
won't do.
IIRC it is doable by only implementing operator ->*() in the smart pointer.

Scott Meyers wrote an article in DDJ discussing the implementation of
that operator (as a template, and using an intermediate temporary, IIRC).
Unfortunately, ddj.com seems to be down so I haven't checked the link now:
http://www.ddj.com/articles/1999/9910/9910b/9910b.htm

I hope this helps,
Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Joseph Seigh
Guest





PostPosted: Sun Jan 30, 2005 11:48 pm    Post subject: Re: Calling member function using a smart pointer and a poin Reply with quote



On 29 Jan 2005 23:10:34 -0500, Howard Gardner <usenet (AT) hgardner (DOT) com> wrote:

Quote:
/*
I'm trying to figure out how to call a class member function using a
pointer to the member function and either a real pointer to the class or
a smart pointer to the class. So far, I've been unable to find the
syntax that I need. I have hacked together a solution that I think I
could use, and that doesn't require that syntax, but the solution is
unlovely and I'd much prefer to find the syntax.

There is one significant constraint: I want to use operator ->() in the
smart pointer, because I intend to exploit the "temporary's lifetime
benefit." If I can't get to that benefit, then there's no reason for me
to write the code that requires this syntax in the first place.

I'd obviously like to avoid burdening either the class or the smart
pointer with any additional syntax if at all possible: the solution that
I hacked together manages to do this, at least as far as I've taken it.
If theres a clean solution that burdens the smart pointer--for instance,
writing operator ->*()--then that might be ok. Burdening the class just
won't do.

Lastly, the signature of the member function is not an issue. In the
context in which I want to make this call, that signature is known. In
other words, if you can show me how to make the sample code below work,
then I can handle the rest of the problem.

The missing syntax is--well--missing. I've commented out a couple of
things that won't do.


Generating a temp is what I do for atomic_ptr. The temp is of a different
type, local_ptr, which is a lighter weight refcounted pointer since it is
non-shared. Using it looks like

atomic_ptr<test> ap;
ap = new test(4);
ap->set(5);
(**ap).set(6);

You need the extra * to dereference the local temp. I haven't figured out a trick
to let you use a single *.

You're not protected from null exceptions if the shared pointer can be set to null.
You'd need to explicitly make a temp copy and test that for null before invoking
the member function, e.g.

local_ptr<test> lp = ap;
if (lp != 0)
lp->set(7);

I don't have exception handling set up in atomic_ptr yet. You can find the
initial pre-alpha release here http://atomic-ptr-plus.sourceforge.net/
There should be another pre-alpha release this week but it's mainly putting
in place the low level atomic primatives api and a lot of cleanup on the
other lock-free stuff.


--
Joe Seigh

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Howard Gardner
Guest





PostPosted: Mon Jan 31, 2005 8:28 pm    Post subject: Re: Calling member function using a smart pointer and a poin Reply with quote

/*
I dont' have access to that article. I presume that his solution looks
pretty much like this version, which is based on overloading global
operator ->*?

I added lck<>, which simulates the locking behavior that motivates
me, but also simulates other interesting behavior (ie, some other
reason for wrapping a member function call).

On the plus side, this doesn't intrude on either ptr<> or example,
and the syntax in call<> is uniform.

It doesn't let me get to the temporary's lifetime benefit, though, so
it's no good to me.

Interestingly, the lifetime of the proxy that operator ->* returns is
also correct for my purposes. Annoyingly, that doesn't appear to do me
much good: what I am trying to do is exploit the temporary's lifetime
benefit given a canonical implementation of a smart pointer.

The fact that global operator ->* has to be so tightly coupled to ptr<>
(uses its name in deduction, and uses its typedef tPointee) is also
unfortunate.

When run, this program produces the output:

ptr::ptr(tPointer)

correctly locked
ptr::operator ->
lck::lck(tPointer) - *LOCK*
lck::operator ->
example::mem_func - *USE*
lck::~lck - *UNLOCK*

real pointers still work
call
example::mem_func - *USE*

smart pointers work too ... kindof
ptr::ptr(tSelf)
call
ptr::ptr(tSelf)
operator ->*
proxy::proxy(tPointer, tPtrMemFunc)
proxy::operator ()
example::mem_func - *USE*
proxy::~proxy
ptr::~ptr
ptr::~ptr

ptr::~ptr
*/

#include <iostream>
using namespace std;

// Some random class that has a member function
struct example
{
void mem_func() const
{cout << "example::mem_func - *USE*" << endl;}
};

// A "locking pointer"
template < typename xPointee >
struct lck
{
typedef lck tSelf;
typedef xPointee tPointee;
typedef xPointee * tPointer;

lck(const tSelf & fThat)
:cPointer(fThat.cPointer)
{cout << "lck::lck(tSelf) - *LOCK*" << endl;}

explicit
lck(tPointer fPointer)
:cPointer(fPointer)
{cout << "lck::lck(tPointer) - *LOCK*" << endl;}

~lck()
{cout << "lck::~lck - *UNLOCK*" << endl;}

tPointee operator *() const
{cout << "lck::operator *" << endl; return *cPointer;}

tPointer operator ->() const
{cout << "lck::operator ->" << endl; return cPointer;}

tPointer cPointer;
};

// A deliberately minimalist "smart pointer"
template < typename xPointee >
struct ptr
{
typedef ptr tSelf;
typedef xPointee tPointee;
typedef xPointee * tPointer;
typedef lck< tPointee > tLck;

ptr(const tSelf & fThat)
:cPointer(fThat.cPointer)
{cout << "ptr::ptr(tSelf)" << endl;}

explicit
ptr(tPointer fPointer)
:cPointer(fPointer)
{cout << "ptr::ptr(tPointer)" << endl;}

~ptr()
{cout << "ptr::~ptr" << endl;}

tPointee operator *() const
{cout << "ptr::operator *" << endl; return *cPointer;}

tLck operator ->() const
{cout << "ptr::operator ->" << endl; return tLck(cPointer);}

tPointer cPointer;
};

// A nullary functor to be returned by overloaded global operator ->*
template < typename xPointee, typename xResult >
struct proxy
{
typedef proxy tSelf;
typedef xPointee tPointee;
typedef xResult tResult;

typedef tPointee * tPointer;
typedef tResult (tPointee::*tPtrMemFunc)() const;

proxy(const tSelf & fThat)
: cPointer(fThat.cPointer), cPtrMemFunc(fThat.cPtrMemFunc)
{cout << "proxy::proxy(tSelf)" << endl;}

proxy(tPointer fPointer, tPtrMemFunc fPtrMemFunc)
: cPointer(fPointer), cPtrMemFunc(fPtrMemFunc)
{cout << "proxy::proxy(tPointer, tPtrMemFunc)" << endl;}

~proxy()
{cout << "proxy::~proxy" << endl;}

tResult operator()() const
{
cout << "proxy::operator ()" << endl;
return (cPointer->*cPtrMemFunc)();
}

tPointer cPointer;
tPtrMemFunc cPtrMemFunc;
};

// overloaded global operator ->*
template < typename xPtr, typename xResult >
proxy< typename xPtr::tPointee, xResult >
operator ->*(xPtr fPtr, xResult (xPtr::tPointee::*fPtrMemFunc)() const)
{
typedef xPtr tPtr;
typedef xResult tResult;
typedef typename tPtr::tPointee tPointee;
typedef proxy< tPointee, tResult > tProxy;
cout << "operator ->*" << endl;
return tProxy(fPtr.cPointer, fPtrMemFunc);
}

// An attempt to call a member function through either a pointer
// or a smart pointer
template < typename xPtrLike, typename xPtrMemFunc >
void
call(xPtrLike fPtrLike, xPtrMemFunc fPtrMemFunc)
{
cout << "call" << endl;

// If used on a real pointer, this does just what it appears to do.
// If used on a ptr<>, this first calls the overloaded global
// operator ->*, then immediately calls operator () on the proxy that
// was returned.
(fPtrLike->*fPtrMemFunc)();
}

int main()
{
example fExample;
ptr< example > fPtr(&fExample);
cout << endl;

cout << "correctly locked" << endl;
fPtr->mem_func();
cout << endl;

cout << "real pointers still work" << endl;
call(&fExample, &example::mem_func);
cout << endl;

cout << "smart pointers work too";
cout << " ... kindof" << endl;
call(fPtr, &example::mem_func);
cout << endl;
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Howard Gardner
Guest





PostPosted: Tue Feb 01, 2005 12:40 am    Post subject: Re: Calling member function using a smart pointer and a poin Reply with quote

Joseph Seigh wrote:
Quote:

Generating a temp is what I do for atomic_ptr. The temp is of a different
type, local_ptr, which is a lighter weight refcounted pointer since it is
non-shared. Using it looks like

atomic_ptr<test> ap;
ap = new test(4);
ap->set(5);
(**ap).set(6);

You need the extra * to dereference the local temp. I haven't figured out a trick
to let you use a single *.

atomic_ptr::operator *() is currently returning an object of
local_ptr<>, which appears to be concerned with reference counting,
garbage collection, and managing a small object pool. It looks like it
would kill all of that functionality if atomic_ptr::operator *()
returned a T &.

I wondered if you could just do away with those features, but it appears
that the garbage collection and the reference counting are central to
the purpose of the library.

Given all of that, I don't think that you can write a canonical
atomic_ptr::operator *() at all, so I'd recommend that you replace
atomic_ptr::operator*() with a non-member function, say local().

That way, given:

int a;
atomic_ptr<int> p(&a);

writing:

*p = 3;

generates a nice clear "operator * is not defined" error, and they can
write:

*local(p) = 3;

to get past it.

I think that it's reasonable to require people writing libraries like
mine to access your functionality exclusively through operator->().

I also think that it's reasonable to require end users either to access
your functionality through operator->() or to use special syntax to get
to it.

I did spend several hours looking at atomic_ptr and trying to solve this
for you, but that's the best I could come up with. Maybe someone else
knows a better way?

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ivan Vecerina
Guest





PostPosted: Tue Feb 01, 2005 12:46 am    Post subject: Re: Calling member function using a smart pointer and a poin Reply with quote

"Howard Gardner" <usenet (AT) hgardner (DOT) com> wrote

Quote:
I dont' have access to that article. I presume that his solution looks
pretty much like this version, which is based on overloading global
operator ->*?
I have no obvious solution to offer, as I haven't been working

this issue. But here's a link that should allow you to access the
article I had mentioned, courtesy of the wayback machine:
http://tinyurl.com/6zwxt
or http://web.archive.org/web/20001027160015/http://www.ddj.com/
articles/1999/9910/9910b/9910b.htm
The described implementation is based on defining a ->* as
a member function...

I hope this helps,
Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form
Brainbench MVP for C++ <> http://www.brainbench.com



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Howard Gardner
Guest





PostPosted: Tue Feb 01, 2005 8:01 pm    Post subject: Re: Calling member function using a smart pointer and a poin Reply with quote

/*
Victory!

This version:

1) does not intrude on either example or ptr<>.
2) depends only on ptr<> having an operator->() defined.
3) gets me to the temporary's lifetime benefit.

I can retrofit other people's smart pointers this way!

I think that this solution is valid for calling any member function that
takes zero parameters, and feel confident that I can extend it to cover
higher arities (my library, The UFO, is only concerned with arities up
to 3 at this point).
*/

#include <iostream>
using namespace std;

// Some random class that has a member function
struct example
{
int mem_func() const
{cout << "example::mem_func" << endl; return 42;}
};

// A deliberately minimalist "smart pointer"
template
<
typename xPointee,
typename xPointer = xPointee *,
typename xStorage = xPointee *
Quote:

struct ptr

{
typedef ptr tSelf;
typedef xPointee tPointee;
typedef xPointer tPointer;
typedef xStorage tStorage;

ptr(const tSelf & fThat)
:cStorage(fThat.cStorage)
{}

explicit
ptr(tPointee * fThat)
:cStorage(fThat)
{}

~ptr()
{}

tPointer operator ->() const
{return tPointer(cStorage);}

tStorage cStorage;
};

// A nullary functor to be returned by overloaded global operator ->*
template < typename xPtr, typename xPtrMemFunc, typename xResult >
struct proxy
{
typedef proxy tSelf;
typedef xPtr tPtr;
typedef xPtrMemFunc tPtrMemFunc;
typedef xResult tResult;

proxy(const tPtr & fPtr, tPtrMemFunc fPtrMemFunc)
: cPtr(fPtr), cPtrMemFunc(fPtrMemFunc)
{}

~proxy()
{}

tResult operator()() const
{
// This line is critical for 2 reasons
// 1. It allows "ptrs returning ptrs returning ..." to work
// 2. It gets me to the temporary's lifetime benefit
return call(cPtr.operator->(), cPtrMemFunc);
}

const tPtr & cPtr;
tPtrMemFunc cPtrMemFunc;
};

// overloaded global operator ->*
template < typename xPtr, typename xResult, typename xClass >
proxy< xPtr, xResult (xClass::*)() const, xResult >
operator ->*(const xPtr & fPtr, xResult (xClass::*fPtrMemFunc)() const)
{
typedef xPtr tPtr;
typedef xResult tResult;
typedef xResult (xClass::*tPtrMemFunc)() const;
typedef proxy< tPtr, tPtrMemFunc, tResult > tProxy;
return tProxy(fPtr, fPtrMemFunc);
}

// Call a member function with either a pointer or a smart pointer
template < typename xPtr, typename xResult, typename xClass >
xResult
call(xPtr fPtr, xResult (xClass::*fPtrMemFunc)() const)
{
// If used on a real pointer, this does just what it appears to do.
// If used on a ptr<>, this first calls the overloaded global
// operator ->*, then immediately calls operator () on the proxy that
// was returned.
return (fPtr->*fPtrMemFunc)();
}

int main()
{
example fExample;

cout << "real pointers work" << endl;
cout << call(&fExample, &example::mem_func) << endl;
cout << endl;

cout << "simple smart pointers work" << endl;
typedef ptr< example > tSimple;
tSimple fSimple(&fExample);
cout << call(fSimple, &example::mem_func) << endl;
cout << endl;

cout << "more complex smart pointers work" << endl;
typedef ptr< example, ptr< example, ptr< example > > > tComplex;
tComplex fComplex(&fExample);
cout << call(fComplex, &example::mem_func) << endl;
cout << endl;
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Joseph Seigh
Guest





PostPosted: Tue Feb 01, 2005 8:04 pm    Post subject: Re: Calling member function using a smart pointer and a poin Reply with quote

On 31 Jan 2005 19:40:18 -0500, Howard Gardner <usenet (AT) hgardner (DOT) com> wrote:

Quote:
Joseph Seigh wrote:


You need the extra * to dereference the local temp. I haven't figured out a trick
to let you use a single *.

atomic_ptr::operator *() is currently returning an object of
local_ptr<>, which appears to be concerned with reference counting,
garbage collection, and managing a small object pool. It looks like it
would kill all of that functionality if atomic_ptr::operator *()
returned a T &.

I wondered if you could just do away with those features, but it appears
that the garbage collection and the reference counting are central to
the purpose of the library.

Both atomic_ptr and local_ptr are reference counting smart pointers.
local_ptr has less overhead since it is meant to be non-shared and
doesn't need as many thread-safety guarantees.

The trick for getting a temp reference to guarantee an object doesn't get
deleted during dereferencing is to not allow the smart pointer to be
dereferenced directly but to force a temp of a different type to be
generated or used and which then allows dereferencing. It is more
transparent with operator -> than operator *.

I could go with more explicit methods as you mention but then I would
lose some of C++'s power of abstraction. I'd rather concentrate on
threading issues than work on the C++ issues (as you can see). I can
get some rather cool lock-free applications from them, though I may
be a little too far ahead on the curve here.

Joe Seigh




--
Joe Seigh

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
David Abrahams
Guest





PostPosted: Tue Feb 01, 2005 9:25 pm    Post subject: Re: Calling member function using a smart pointer and a poin Reply with quote

Howard Gardner <usenet (AT) hgardner (DOT) com> writes:

Quote:
/*
I'm trying to figure out how to call a class member function using a
pointer to the member function and either a real pointer to the class or
a smart pointer to the class. So far, I've been unable to find the
syntax that I need. I have hacked together a solution that I think I
could use, and that doesn't require that syntax, but the solution is
unlovely and I'd much prefer to find the syntax.

There is one significant constraint: I want to use operator ->() in the
smart pointer, because I intend to exploit the "temporary's lifetime
benefit." If I can't get to that benefit, then there's no reason for me
to write the code that requires this syntax in the first place.

I'd obviously like to avoid burdening either the class or the smart
pointer with any additional syntax if at all possible: the solution that
I hacked together manages to do this, at least as far as I've taken it.
If theres a clean solution that burdens the smart pointer--for instance,
writing operator ->*()--then that might be ok. Burdening the class just
won't do.

Lastly, the signature of the member function is not an issue. In the
context in which I want to make this call, that signature is known. In
other words, if you can show me how to make the sample code below work,
then I can handle the rest of the problem.

The missing syntax is--well--missing. I've commented out a couple of
things that won't do.

Applying the Fundamental Theorem of Software Engineering (**), an extra
level of indirection solves the problem:

#include <boost/mpl/bool.hpp>
#include <boost/type_traits/is_pointer.hpp>

template < typename xPtrLike, typename xPtrMemFunc >
void call(xPtrLike, xPtrMemFunc);

namespace call_impl
{
template <class Ptr, class Pmf>
inline void do_call(Ptr p, Pmf f, boost::mpl::true_)
{
(p->*f)();
}

template <class Ptr, class Pmf>
inline void do_call(Ptr p, Pmf f, boost::mpl::false_)
{
::call(p.operator->(), f);
}
}

template < typename xPtrLike, typename xPtrMemFunc >
void
call(xPtrLike fPtrLike, xPtrMemFunc fPtrMemFunc)
{
cout << "call" << endl;
call_impl::do_call(fPtrLike, fPtrMemFunc, boost::is_pointer }


(**) Thanks to Butler Lampson and Andrew Koenig.

HTH,
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Howard Gardner
Guest





PostPosted: Tue Feb 01, 2005 11:27 pm    Post subject: Re: Calling member function using a smart pointer and a poin Reply with quote

David Abrahams wrote:
Quote:

Applying the Fundamental Theorem of Software Engineering (**), an extra
level of indirection solves the problem:

#include <boost/mpl/bool.hpp
#include
template < typename xPtrLike, typename xPtrMemFunc
void call(xPtrLike, xPtrMemFunc);

namespace call_impl
{
template inline void do_call(Ptr p, Pmf f, boost::mpl::true_)
{
(p->*f)();
}

template <class Ptr, class Pmf
inline void do_call(Ptr p, Pmf f, boost::mpl::false_)
{
::call(p.operator->(), f);
}
}

template < typename xPtrLike, typename xPtrMemFunc
void
call(xPtrLike fPtrLike, xPtrMemFunc fPtrMemFunc)
{
cout << "call" << endl;
call_impl::do_call(fPtrLike, fPtrMemFunc, boost::is_pointer }


(**) Thanks to Butler Lampson and Andrew Koenig.

HTH,

It does indeed. Thank you.

Why are you writing the ::call that way? Is it just an artifact left
over from some point in time when do_call was also named call? Is it
because the name call is suspiciously short and likely to have been used
for other purposes? Is it meant to prevent ADL from being invoked? Is it
completely spurious?

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Howard Gardner
Guest





PostPosted: Wed Feb 02, 2005 9:55 am    Post subject: Re: Calling member function using a smart pointer and a poin Reply with quote

Joseph Seigh wrote:
Quote:
atomic_ptr::operator *() is currently returning an object of
local_ptr<>, which appears to be concerned with reference counting,
garbage collection, and managing a small object pool. It looks like it
would kill all of that functionality if atomic_ptr::operator *()
returned a T &.

I wondered if you could just do away with those features, but it appears
that the garbage collection and the reference counting are central to
the purpose of the library.


Both atomic_ptr and local_ptr are reference counting smart pointers.
local_ptr has less overhead since it is meant to be non-shared and
doesn't need as many thread-safety guarantees.

The trick for getting a temp reference to guarantee an object doesn't get
deleted during dereferencing is to not allow the smart pointer to be
dereferenced directly but to force a temp of a different type to be
generated or used and which then allows dereferencing. It is more
transparent with operator -> than operator *.

I could go with more explicit methods as you mention but then I would
lose some of C++'s power of abstraction. I'd rather concentrate on
threading issues than work on the C++ issues (as you can see). I can
get some rather cool lock-free applications from them, though I may
be a little too far ahead on the curve here.

Joe Seigh

You provide the interesting behavior through an overloaded operator->(),
so my library will be able to use it. I guess that's the limit of my
proper concern. Your end users can make you take the CONFUSING AND EVIL
operator *() away in due course :)

I read an article on slashdot about the impact that multicore cpu's are
likely to have on software desing. The author argued that cache size
increases are the only likely benefit that single threaded apps are
going to get in the near future, that only software that multiprocesses
gracefully is going to get the big performance gains that we've all
grown accustomed to, and that we programming types can therefore expect
to start feeling significant pressure to improve our use of
multiprocessing very soon. You may find the great unwashed masses
looking at your stuff sooner than you think! (No, I didn't save the link.)

For my own part, I thought that his case was compelling enough to put
some effort into making sure that applications using my library will be
able to use multiprocessing to good effect.

My library deals with implementing object models: managing logical
storage, transactions, referential integrity, martialling, persistence,
distribution of data, distribution of operations, and so on. It's at a
higher level of abstraction than locking (or not locking, as the case
may be).

I have tried very hard to make it orthogonal to multithreading in
particular: I accept a smart pointer wherever I think that locking may
be wanted or needed. This last flurry of activity, for instance, came
from the fact that my function adapters wouldn't take smart pointers to
classes in place of real pointers to classes. I think that my users will
want them to, so now they will. I've also tried very hard to make sure
that the user can make threads happen when that's wanted. For example,
multiple lookups on the same object store can occur simultaneously in
seperate threads if the user feeds me the right type of object.

Just as you're not particularly enthused about spending time on C++
packaging, I'm not real keen on futzing around with smart pointers.
They're building blocks for me. Consequently the ones that I've written
aren't particularly slick. Loki's are definitely better, and I imagine
that boost's are too: there are probably many other collections of smart
pointers that blow mine away. I'm afraid that mine are particularly
pedestrian in the realm of thread synchronization, and I've never even
TRIED to do lock free stuff. I'll fix that if I have to, but I'd really
rather not thanks.

Which brings me back to atomic_ptr. I'd have added it to my test cases
(smart pointers that I test against) already if I could compile it. What
I can't compile, obviously, is atomix.h. What compiler are you using?
Would it be possible to write that in C or C++? Even if it spiked
performance, it would let me test between now and whenever someone ports
it to my build environment (comeau/mingw/win32).

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Joseph Seigh
Guest





PostPosted: Wed Feb 02, 2005 8:10 pm    Post subject: Re: Calling member function using a smart pointer and a poin Reply with quote

On 2 Feb 2005 04:55:11 -0500, Howard Gardner <usenet (AT) hgardner (DOT) com> wrote:

Quote:

You provide the interesting behavior through an overloaded operator->(),
so my library will be able to use it. I guess that's the limit of my
proper concern. Your end users can make you take the CONFUSING AND EVIL
operator *() away in due course Smile

Probably. I didn't notice the problem with * dereferencing right away
since you don't generally use * to dereference classes or structs. I
haven't quite decided what to do at this point yet. I've been
putting it off since I wanted to keep everything pointer like as
possible. The local() function something like you suggested sounds
like a possibility if I don't find a trick to make * work properly.

[...]
Quote:


Just as you're not particularly enthused about spending time on C++
packaging, I'm not real keen on futzing around with smart pointers.
They're building blocks for me. Consequently the ones that I've written
aren't particularly slick. Loki's are definitely better, and I imagine
that boost's are too: there are probably many other collections of smart
pointers that blow mine away. I'm afraid that mine are particularly
pedestrian in the realm of thread synchronization, and I've never even
TRIED to do lock free stuff. I'll fix that if I have to, but I'd really
rather not thanks.

The area of application for atomic_ptr is slightly different than the
other smart pointers. It's more of a way of dealing with the
readers/writers problem. shared_ptr gets used for that also but you
have to be aware of the "thread-safe as int" that shared_ptr has. What
atomic_ptr is not is a general replacement for all pointers. You
wouldn't use it for all objects just as you wouldn't use mutexes for
all object accesses. You use them where appropiate. And there
are some C++ issues I've been avoiding or ignoring for now.

Quote:

Which brings me back to atomic_ptr. I'd have added it to my test cases
(smart pointers that I test against) already if I could compile it. What
I can't compile, obviously, is atomix.h. What compiler are you using?
Would it be possible to write that in C or C++? Even if it spiked
performance, it would let me test between now and whenever someone ports
it to my build environment (comeau/mingw/win32).

atomix.h abstracts out the platform specific stuff. The version currently
distributed is for Linux on i586 with gcc compiler. Though I orginally
had atomic_ptr working on win32 I haven't ported the new atomix.h api to
win32. There are some issues with how vc++ deals with optimization around
inline assembler that can cause problems with multi-threaded code. For
most stuff you can all external routines to get around that but for things
like a simple memory barrier instruction, doing an external call can make
it more expensive than you want.

--
Joe Seigh

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
David Abrahams
Guest





PostPosted: Thu Feb 03, 2005 10:34 am    Post subject: Re: Calling member function using a smart pointer and a poin Reply with quote

Howard Gardner <usenet (AT) hgardner (DOT) com> writes:

Quote:
Why are you writing the ::call that way? Is it just an artifact left
over from some point in time when do_call was also named call?

Naw, you're way off.

Quote:
Is
it because the name call is suspiciously short and likely to have
been used for other purposes?

Gettin' warmer, doc!

Quote:
Is it meant to prevent ADL from being invoked?

Ooh, you're red hot, doc!

Quote:
Is it completely spurious?

It's wabbit season.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.