473,883 Members | 2,205 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

How does dereference operator overloading really work?

Is there a good write on this. The textbooks I have fluff over
on this? Specifically, I trying to dereference with 2 levels
of type conversion not 1, i.e.

X<T> -> z => Y<T> -> z => T* -> z
and
*X<T> => *Y<T> => *T
The Y<T> conversion has to be done as an expression temp. It cannot be done
inside a method body for X.

I think I sort of had it working for the -> operator but the same
technique doesn't work for the * operator. The * appears to getting
consumed.

Joe Seigh
Jul 19 '05
18 9731


"David B. Held" wrote:

If you are writing a smart pointer, overloading operator->
is one of the most important things you need to do. But
why write YASP (Yet Another Smart Pointer)? Do take
a look at Loki::SmartPtr before reinventing the wheel for
the Nth time.


No, this is an atomic thread-safe smart pointer. You're
guaranteed to point to a valid object or null no matter
what (the same guarantee that Java pointers have). No
other C++ smart pointer can make that claim. They require
you to own or have a lock on a smart pointer to access it
or to dereference it.

But this whole thing of C++ treating -> differently from
* has me spooked and I have no explanation of what is
going on. When C++ evaluate an expression, that expression
is replaced by a value of the expression return type. Except
when that expression is a -> expression. Then just the left
hand part of the expression is replaced, the -> is left in,
and the expression is re-evaluated.

Joe Seigh
Jul 19 '05 #11
"Joe Seigh" <js*******@xema ps.com> wrote in message
news:3F******** *******@xemaps. com...
[...]
No, this is an atomic thread-safe smart pointer. You're
guaranteed to point to a valid object or null no matter
what (the same guarantee that Java pointers have). No
other C++ smart pointer can make that claim.
LOL!!!
They require you to own or have a lock on a smart
pointer to access it or to dereference it.
You really do need to read Modern C++ Design, and pay
close attention to the chapter on smart pointers.
But this whole thing of C++ treating -> differently from
* has me spooked and I have no explanation of what is
going on.
Simple. operator->() for smart pointers should always
return an underlying pointer. operator*() should return
a reference to the pointed-to object.
When C++ evaluate an expression, that expression
is replaced by a value of the expression return type.
Except when that expression is a -> expression. Then
just the left hand part of the expression is replaced, the
-> is left in, and the expression is re-evaluated.


That's so that it's easy to write operator->(). Imagine if
you had to compute struct member offsets yourself.

Dave
Jul 19 '05 #12


"David B. Held" wrote:

"Joe Seigh" <js*******@xema ps.com> wrote in message
news:3F******** *******@xemaps. com...
[...]
No, this is an atomic thread-safe smart pointer. You're
guaranteed to point to a valid object or null no matter
what (the same guarantee that Java pointers have). No
other C++ smart pointer can make that claim.


LOL!!!


Atomic means that for the expression "p->a" where p is a
smart pointer, a valid value (or null pointer exception)
will be returned even if some other thread deletes or
modifies p during the evaluation of that expression. What
will not happen is a value returned from storage that
has been reallocated as another object in the meantime.
AFAIK all other smart pointers restrict what can happen
to p during the evaluation of such an expression.

The trick here (among other things) is to generate a local
copy of the pointer as an expression temp during the
evaluation of the expression. Since temps aren't dtored
until after the the evaluation of the expression, the
validity of the raw pointer value is guaranteed.

The reason you don't see any of the other smart pointers
using this trick is efficient thread-safe copying of the
smart pointer is non-trivial.

Joe Seigh
Jul 19 '05 #13


Rob Williscroft wrote:
We really need to know what you are trying to do, otherwise
all you can expect is guess, If you havent got any code to show
perhapse give an example of the code whant to write and what you
want it to actually do.


Here's some code that illustrates the problem. It is not a smart pointer
implementation. Just an illustration of a particular operator overloading
issue.

template<typena me T> class X; // forward declare

template<typena me T> class Y {
T * ptr;
public:
Y(X<T> & z) {
ptr = z.ptr;
}
T * operator ->() { return ptr; }
T & operator *() { return *ptr; }
};

template<typena me T> class X {
friend class Y<T>;
T * ptr;
public:
X(T * p = 0) : ptr(p) {}
Y<T> operator ->() { return Y<T>(*this); }
Y<T> operator *() { return Y<T>(*this); }
};

class Item {
public:
Item(int x = 0) : z(x) {}
int z;
};

int main(int argc, char *argv[]) {
X<Item> p = new Item(99);
Item k;
int n;

n = p->z;

k = **p; // why 2 *'s and not 2 ->'s above?

n = Y<Item>(p)->z; // this works

n = (Y<Item>(p))->z; // this doesn't, vc++6.0 complains

return 0;
}

Joe Seigh
Jul 19 '05 #14
Joe Seigh wrote in news:3F******** *******@xemaps. com:


Rob Williscroft wrote:

[snip]

Here's some code that illustrates the problem. It is not a smart
pointer implementation. Just an illustration of a particular operator
overloading issue.

[snip]

int main(int argc, char *argv[]) {
X<Item> p = new Item(99);
Item k;
int n;

n = p->z;

k = **p; // why 2 *'s and not 2 ->'s above?
Because thats the way operator *() works, You can argue that its
wrong (or not the most versitile way it could work) but changing
it would break code.

n = Y<Item>(p)->z; // this works

n = (Y<Item>(p))->z; // this doesn't, vc++6.0 complains
Get a better compiler VC 6.0 is quiet old now, VC 7.1 handles it fine
BTW. Also this is clearly a bug so maybe its fixed by a service pack.

return 0;
}


Unfortunatly we all have to work with the language as its defined,
"warts and all", Its even worse for VC 6.0 users as it's a pre-standard
compiler.

You're example illustrated what you can't do with the language.

Perhapse an example of what you wan't to achive would help here,
i.e. What insterface you want to expose and some examples of the
usage you expect.

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 19 '05 #15
"Joe Seigh" <js*******@xema ps.com> wrote in message
news:3F******** *******@xemaps. com...

"David B. Held" wrote:
[...]
LOL!!!
Atomic means that for the expression "p->a" where p
is a smart pointer, a valid value (or null pointer exception)
will be returned even if some other thread deletes or
modifies p during the evaluation of that expression.


I wasn't laughing at the idea of a thread-safe pointer.
I was laughing at the idea that you know every other
type of smart pointer in existence. There is no doubt
in my mind that there are hundreds of smart pointer
types that you have never seen because they have not
been released to the public. So to say that: "No
other C++ smart pointer can make that claim" is just
ridiculous.
What will not happen is a value returned from storage
that has been reallocated as another object in the
meantime.
I can see why you want to do that, but ask yourself if
this is the right level of locking. After all, most of the
time that you want to access a resource in multiple
threads, you also want to lock it for longer than the
duration of one pointer access. So, for instance, if
you do two successive pointer accesses into the same
struct, it seems to me that you are locking the pointee
twice, instead of once. So what are you paying for
this "convenienc e"?
AFAIK all other smart pointers restrict what can
happen to p during the evaluation of such an
expression.
And how many smart pointers do you know about?
The other question is, if other smart pointers typically
don't provide the functionality you wish to add, could
there be a good reason for doing not so?
The trick here (among other things) is to generate a
local copy of the pointer as an expression temp during
the evaluation of the expression. Since temps aren't
dtored until after the the evaluation of the expression,
the validity of the raw pointer value is guaranteed.
I don't see how that prevents another pointer to the
same resource from deleting the resource out from
under you. After all, the standard is thread-agnostic,
so it makes no guarantees about program behaviour
in the presence of multiple threads. In particular, I
don't think it follows at all that a temp has some magical
property which influences other threads. But I could
just be misunderstandin g your explanation.
The reason you don't see any of the other smart
pointers using this trick is efficient thread-safe copying
of the smart pointer is non-trivial.


I think there's more reasons than that.

Dave
Jul 19 '05 #16

"David B. Held" wrote:
[...]
The other question is, if other smart pointers typically
don't provide the functionality you wish to add, could
there be a good reason for doing not so?


His pointer provides STRONG thread-safety, not {more common} BASIC one.
It's needed to sort of emulate {revised} Java volatile references with
automatic garbage collection for things like:

http://www.hpl.hp.com/personal/Hans_...c/example.html

or similar stuff using DCAS/whatever (avoiding blocking; "lock-free").

regards,
alexander.
Jul 19 '05 #17


"David B. Held" wrote:

"Joe Seigh" <js*******@xema ps.com> wrote in message
news:3F******** *******@xemaps. com...

"David B. Held" wrote:
[...]
LOL!!!
Atomic means that for the expression "p->a" where p
is a smart pointer, a valid value (or null pointer exception)
will be returned even if some other thread deletes or
modifies p during the evaluation of that expression.


I wasn't laughing at the idea of a thread-safe pointer.
I was laughing at the idea that you know every other
type of smart pointer in existence. There is no doubt
in my mind that there are hundreds of smart pointer
types that you have never seen because they have not
been released to the public. So to say that: "No
other C++ smart pointer can make that claim" is just
ridiculous.


Well, there's "Lock-Free Reference Counting" by Detlifs et al,
but I don't know anyone using that since it requires something
like the MC68020 with a DCAS instruction. There's weighted
reference counting and something equivalent to it but my
impression is that they weren't efficient enough for practical
use. Reference counting is a form of GC, but you could use
another form of GC such as RCU or Maged Michael's hazard
pointers to make the refcount increment safe. Interestingly
enough if you use Michael's double check logic in conjuction
with LL/SC or ldwarx/stwcx instructions you can also increment
the refcount safely.
What will not happen is a value returned from storage
that has been reallocated as another object in the
meantime.
I can see why you want to do that, but ask yourself if
this is the right level of locking. After all, most of the
time that you want to access a resource in multiple
threads, you also want to lock it for longer than the
duration of one pointer access. So, for instance, if
you do two successive pointer accesses into the same
struct, it seems to me that you are locking the pointee
twice, instead of once. So what are you paying for
this "convenienc e"?


There's two classes of this pointer. A global shared pointer
class and a local non shared pointer class. The global
is for mainly for use in the actual data structure and the
local is for threads to access the struction. The local
pointers have overhead equal to the non-atomic threadsafe
pointers.

It's not so much that lock-free pointers are all that fast
by themselves, but they do let you implement other lock-free
solutions that do blow conventional locking solutions out
of the water.
AFAIK all other smart pointers restrict what can
happen to p during the evaluation of such an
expression.
And how many smart pointers do you know about?
The other question is, if other smart pointers typically
don't provide the functionality you wish to add, could
there be a good reason for doing not so?


Boost shared_ptr mainly. Either they didn't know how
to without adding more overhead than they wanted or they
decided it wasn't needed since they were requiring a
higher level of locking anyway. The latter is a
perfectly valid reason and seems to be the official
reason given.
The trick here (among other things) is to generate a
local copy of the pointer as an expression temp during
the evaluation of the expression. Since temps aren't
dtored until after the the evaluation of the expression,
the validity of the raw pointer value is guaranteed.


I don't see how that prevents another pointer to the
same resource from deleting the resource out from
under you. After all, the standard is thread-agnostic,
so it makes no guarantees about program behaviour
in the presence of multiple threads. In particular, I
don't think it follows at all that a temp has some magical
property which influences other threads. But I could
just be misunderstandin g your explanation.


The temp local copy of the pointer prevents the reference
count from going to zero during the evaluation of the
expression. If some other thread had deleted the global
pointer during the evaluation of the expression then the
dtor of the temp copy would actually delete the object
after the expression was evaluated, not during or before.

But I'm not trying sell anyone on this particular smart pointer.
The OP is about some compiler or language behavior I'm seeing
when trying to force the temp copy to be generated. It could
be this whole double conversion technique is not really supported
in C++ and I'd have do it in C instead.

Joe Seigh
Jul 19 '05 #18
On Sun, 21 Sep 2003 18:11:52 GMT, Joe Seigh <js*******@xema ps.com>
wrote:
Is there a good write on this. The textbooks I have fluff over
on this? Specifically, I trying to dereference with 2 levels
of type conversion not 1, i.e.

X<T> -> z => Y<T> -> z => T* -> z
and
*X<T> => *Y<T> => *T
The Y<T> conversion has to be done as an expression temp. It cannot be done
inside a method body for X.

I think I sort of had it working for the -> operator but the same
technique doesn't work for the * operator. The * appears to getting
consumed.


operator-> is a bit odd. It's not that operator* gets consumed, but
that operator-> is recursive.

I think you need smart references, which don't exist yet. e.g.

smart_reference <T> operator*();

where the reference behaves almost exactly as if it were a T&, but you
can do stuff in the destructor (such as unlock a mutex or decrement a
reference count). Since you can't overload "operator." this isn't
currently possible.

Even without operator., you can still write an acceptable version of
smart_reference by providing operator T&, operator=, etc. You just
won't be able to do:

(*p).doit();

You could easily argue that users should write:

p->doit();

anyway, so you might not consider it a problem.

Tom
Jul 19 '05 #19

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

16
2629
by: Edward Diener | last post by:
Is there a way to override the default processing of the assignment operator for one's own __value types ? I realize I can program my own Assign method, and provide that for end-users of my class, but I would like to use internally my own = operator for some of my value types, so I can say "x = y;" rather than "x.Assign(y);". The op_Assign operator seems impossibly broken since it takes __value copies of the two objects. Perhaps there is...
16
3103
by: gorda | last post by:
Hello, I am playing around with operator overloading and inheritence, specifically overloading the + operator in the base class and its derived class. The structure is simple: the base class has two int memebers "dataA", "dataB". The derived class has an additional int member "dataC". I am simply trying to overload the + operator so that 'adding' two objects will sum up the corresponding int members.
4
1783
by: PKH | last post by:
This is a part of an autopointer template i'm using. I originally had a Get() member that returned the pointer, but thought it would nice to be able to use the -> operator. The question is why does the following line work, and call cAP.m_pcPointer->Testing() ? cAP->Testing(); // ??? cAP-> returns a CTest*, so it looks to me like the line reads cAP.m_pcPointer <whitespace> Testing(), but it actually does
51
3619
by: Jojo | last post by:
Is there any way to get to the left-hand side of an operator? Consider the following (this is not meant to be perfect code, just an example of the problem): class Matrix { public: int data; Matrix() {}
6
5432
by: TuxC0d3 | last post by:
Hi! I'm diving into the some more ++ specific aspects of c++ (and finally accepting that c++ is more than "a plus added to c" :), so that means using namespaces, templates, std::strings, lists, vectors, operator overloading and what not.. And i was wondering if there is a way to override the global dereference operator, so to be able to check the address that one tries to dereference. This gives the ability to throw an exception when...
14
468
by: Bit byte | last post by:
Came accross the ff code: double array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; std::vector<double> values(array, array + 9); //<- is this a 2D vector ?
2
2925
by: allan.mcrae | last post by:
I am having trouble with overloading the += operator when template parameters are used. I have a class holding an array (called "derived" in the following example) which derives from a base class ("base"). I want to be able to add: 1) any derived array holding class to any other derived array holding class 2) any derived array holding class to a literal value (e.g int, double, etc) for which addition is defined for the type in the...
6
3558
by: Bill foust | last post by:
I'm running into a situation there I think an operator overload would solve the issue, but I'm unable to make it work for some reason. If anyone can help here I would appreciate it. I have a base class that is common to many other classes. public class Base .... end class I have 2 seperate classes that inherit from base
22
3637
by: clicwar | last post by:
A simple program with operator overloading and copy constructor: #include <iostream> #include <string> using namespace std; class Vector { private: float x,y; public: Vector(float u, float v);
0
9953
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9799
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10768
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
7980
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
7137
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5808
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
6009
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4623
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
4231
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.