Problem using 'shared_ptr<T>::operator impl-defined-type()'
With Borland 5.5.1, I'm not having any luck using a shared_ptr in a boolean
context. The compiler complains that the 'if' condition below contains an
"Illegal structure operation". Is this a known deficiency with my compiler?
-Greg Hickman
#include
--- In Boost-Users@y..., "Hickman, Greg"
With Borland 5.5.1, I'm not having any luck using a shared_ptr in a boolean context. The compiler complains that the 'if' condition below contains an "Illegal structure operation". Is this a known deficiency with my compiler?
-Greg Hickman
#include
int main(int argc, char* argv[]) { boost::shared_ptr<int> intp;
if (intp) // error here
Change this to: if (intp.get())
;
return 0; }
From: "Hickman, Greg"
With Borland 5.5.1, I'm not having any luck using a shared_ptr in a boolean context. The compiler complains that the 'if' condition below contains an "Illegal structure operation". Is this a known deficiency with my compiler?
Yes, Borland does have trouble with this construct (i.e. p && q fails), but simple uses such as your program work for me; once again, have you installed the service packs? :-)
I've written my own smart pointer classes but have mostly switched over to
Boost. What I've wondered is why the Boost smart pointers use various
methods to achieve this boolean conversion instead of a single method of the
form
operator void const * () const { return px; }
This enables the standard boolean uses ("if (ptr)", "if (!ptr)") and also
allows direct comparison between a raw pointer and the shared pointer. It
also doesn't seem to allow bad leakage of the pointer because a (void
const*) can only be used for comparison. I've looked through the news groups
and Boost documentation and seen no mention of this.
"Peter Dimov"
From: "Hickman, Greg"
With Borland 5.5.1, I'm not having any luck using a shared_ptr in a boolean context. The compiler complains that the 'if' condition below contains an "Illegal structure operation". Is this a known deficiency with my compiler?
Yes, Borland does have trouble with this construct (i.e. p && q fails), but simple uses such as your program work for me; once again, have you installed the service packs? :-)
I've written my own smart pointer classes but have mostly switched over to Boost. What I've wondered is why the Boost smart pointers use various methods to achieve this boolean conversion instead of a single method of
From: "Alan M. Carroll, CodeSlinger"
form
operator void const * () const { return px; }
This enables the standard boolean uses ("if (ptr)", "if (!ptr)") and also allows direct comparison between a raw pointer and the shared pointer. It also doesn't seem to allow bad leakage of the pointer because a (void const*) can only be used for comparison. I've looked through the news groups and Boost documentation and seen no mention of this.
delete ptr; // ;-) In the general case unwanted comparisons are a problem, too.
"Peter Dimov"
From: "Alan M. Carroll, CodeSlinger"
operator void const * () const { return px; }
delete ptr; // ;-)
In the general case unwanted comparisons are a problem, too.
According to (an admittedly old) spec (Annotated C++), 5.3.4 says "A pointer to constant cannot be deleted" in reference to the delete operator. Since the value returned by this operator is a pointer to constant void, the statement you have should generate a compiler error. I've tested in on MS-VC 6 (SP5) and it does not compile. int main(int argc, char **argv) { void const * ptr; delete ptr; return 0; } yields error C2664: 'delete' : cannot convert parameter 1 from 'const void *' to 'void *' What kind of unwanted comparisons can occur? The ability to compare directly to a raw pointer seems like a feature. It would seem that this just allows the same comparisons one would get with a raw pointer, which makes shared_ptr easier to drop in as a replacement.
"Peter Dimov"
wrote in message news:019701c264b3$8af21640$1d00a8c0@pdimov2... From: "Alan M. Carroll, CodeSlinger"
operator void const * () const { return px; }
delete ptr; // ;-)
In the general case unwanted comparisons are a problem, too.
According to (an admittedly old) spec (Annotated C++), 5.3.4 says "A
From: "Alan M. Carroll, CodeSlinger"
to constant cannot be deleted" in reference to the delete operator. Since the value returned by this operator is a pointer to constant void, the statement you have should generate a compiler error. I've tested in on MS-VC 6 (SP5) and it does not compile.
What kind of unwanted comparisons can occur? The ability to compare
5.3.5/2 (ISO): "[Note: a pointer to a const type can be the operand of a delete-expression; ...]" directly
to a raw pointer seems like a feature. It would seem that this just allows the same comparisons one would get with a raw pointer, which makes shared_ptr easier to drop in as a replacement.
The conversion to "void const *" allows any comparisons between two objects that define such a conversion: two different smart pointers to unrelated types, shared_ptr to std::cout, and so on. Even in a shared_ptr<T>-only context, it makes it difficult to not provide operator>=, for instance. It is true that in this particular context a void const * conversion is somewhat less evil as shared_ptr is a pointer, but many undesirable properties still remain. That aside, do you really have code that depends on a specific conversion to void const *?
"Peter Dimov"
From: "Alan M. Carroll, CodeSlinger"
"Peter Dimov"
wrote in message news:019701c264b3$8af21640$1d00a8c0@pdimov2... From: "Alan M. Carroll, CodeSlinger"
operator void const * () const { return px; }
delete ptr; // ;-)
In the general case unwanted comparisons are a problem, too.
5.3.5/2 (ISO): "[Note: a pointer to a const type can be the operand of a delete-expression; ...]"
So, you agree that "delete ptr" is not a problem for the cast to (void const *)?
The conversion to "void const *" allows any comparisons between two objects that define such a conversion: two different smart pointers to unrelated types, shared_ptr to std::cout, and so on. Even in a shared_ptr<T>-only context, it makes it difficult to not provide operator>=, for instance.
It is true that in this particular context a void const * conversion is somewhat less evil as shared_ptr is a pointer, but many undesirable properties still remain.
That aside, do you really have code that depends on a specific conversion to void const *?
Not directly. This issue came up with earlier version of Boost smart_ptr that didn't have the methods necessary for things like if (ptr) { /* stuff */ } The conversion provides this. It also supports the idiom if (ptr == 0) { /* stuff */ } which I believe is not possible with the current Boost smart_ptr. I've also had issues with comparisons between shared_ptr<T> and T*. While this can be avoided through minor changes of habit, it is much easier for me to overcome the resistance of fellow programmers if they can literally drop in shared_ptr<T> instead of T* and constructs such as the above occur frequently enough to be an issue. While not optimally safe, I judge it better to get a weaker version of smart pointer than no smart pointer at all. But I understand the Boost point of view now.
From: "Alan M. Carroll"
5.3.5/2 (ISO): "[Note: a pointer to a const type can be the operand of a delete-expression; ...]"
So, you agree that "delete ptr" is not a problem for the cast to (void const *)?
No, I don't. Deleting a void const * is not (directly) prohibited by the standard, and some compilers let it through without even a warning.
That aside, do you really have code that depends on a specific conversion to void const *?
Not directly. This issue came up with earlier version of Boost smart_ptr that didn't have the methods necessary for things like if (ptr) { /* stuff */ }
This is now supported.
The conversion provides this. It also supports the idiom if (ptr == 0) { /* stuff */ } which I believe is not possible with the current Boost smart_ptr. I've also had issues with comparisons between shared_ptr<T> and T*. While this can be avoided through minor changes of habit, it is much easier for me to overcome the resistance of fellow programmers if they can literally drop in shared_ptr<T> instead of T* and constructs such as the above occur frequently enough to be an issue.
OK, but you are arguing for shared_ptr<T> to T* comparisons, not for a void const * conversion. The right way to support these comparisons is by defining the appropriate operators. If you want to "lobby" for shared_ptr<T> == T*, please do so on the developer list, I've no problem with that. :-) In my opinion this is a "neutral" feature, i.e. the pros and cons balance themselves. A smart pointer is different enough from T* so it sometimes even helps to _not_ make it a drop-in replacement and prefer the more explicit p.get() == q for mixed comparisons. The if(p) syntax supports the important idiom: if(shared_ptr<T> p = make_shared(q)) { // ... }
"Peter Dimov"
OK, but you are arguing for shared_ptr<T> to T* comparisons, not for a
void
const * conversion. The right way to support these comparisons is by defining the appropriate operators. If you want to "lobby" for shared_ptr<T> == T*, please do so on the developer list, I've no problem with that. :-)
I'm not arguing for anything. This is a technique I picked up that I found useful because it, in a single method, provides a number of useful features. I was simply curious as to why Boost didn't use the technique. I presumed that it was obvious enough that it had been considered and rejected. After searching, I was unable to find any rational for not using it, so I asked here. My goal was to understand the logic behind that decision. You have explained clearly why you prefer to not use it in a generic smart pointer implementation so that achieves my goal.
From: "Alan M. Carroll, CodeSlinger"
"Peter Dimov"
wrote in message news:005401c26614$5b478cb0$1d00a8c0@pdimov2... OK, but you are arguing for shared_ptr<T> to T* comparisons, not for a
void
const * conversion. The right way to support these comparisons is by defining the appropriate operators. If you want to "lobby" for shared_ptr<T> == T*, please do so on the developer list, I've no problem with that. :-)
I'm not arguing for anything. This is a technique I picked up that I found useful because it, in a single method, provides a number of useful features. I was simply curious as to why Boost didn't use the technique. I presumed that it was obvious enough that it had been considered and rejected. After searching, I was unable to find any rational for not using it, so I asked here. My goal was to understand the logic behind that decision. You have explained clearly why you prefer to not use it in a generic smart pointer implementation so that achieves my goal.
I see. :-) In case my explanation didn't really convince you, consider that ((void const *)p) == q is, in general, not the same as p == q when p and q are pointers to different types. It appears to work in most cases and that makes the problem even harder to find when it finally surfaces.
participants (5)
-
Alan M. Carroll
-
Alan M. Carroll, CodeSlinger
-
david_at_2good
-
Hickman, Greg
-
Peter Dimov