Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Assignment operator self-assignment check

Reply
Thread Tools

Assignment operator self-assignment check

 
 
Frederick Gotham
Guest
Posts: n/a
 
      09-21-2006
Noah Roberts posted:

>> int array1[5], array2[5], *p1 = array1+3, *p2 = array2+2;
>>
>> p2 > p1; /* UB! */

>
> I don't really even know what you are talking about here as your
> clipping has completely removed context but I can see right off that
> there is no undefined behavior in the above code. I can't imagine why
> you think there is.



The above code snippet invokes undefined behaviour because the two pointers
which it compares do _not_ point to the same array.

--

Frederick Gotham
 
Reply With Quote
 
 
 
 
Noah Roberts
Guest
Posts: n/a
 
      09-21-2006

Frederick Gotham wrote:
> Noah Roberts posted:
>
> >> int array1[5], array2[5], *p1 = array1+3, *p2 = array2+2;
> >>
> >> p2 > p1; /* UB! */

> >
> > I don't really even know what you are talking about here as your
> > clipping has completely removed context but I can see right off that
> > there is no undefined behavior in the above code. I can't imagine why
> > you think there is.

>
>
> The above code snippet invokes undefined behaviour because the two pointers
> which it compares do _not_ point to the same array.


Why would that invoke undefined behavior?? We can't tell offhand what
the result of the operation you've labeled is going to be (well
actually it does nothing but lets assume you assigned the result to a
boolean) and the information is rather useless, but there is no
undefined behavior that I see.

 
Reply With Quote
 
 
 
 
Frederick Gotham
Guest
Posts: n/a
 
      09-21-2006
Noah Roberts posted:

> Why would that invoke undefined behavior??


Forgive me, the behaviour is "unspecified" rather than "undefined".

Page 88 of the current Standard:

| If two pointers p and q of the same type point to different objects
| that are not members of the same object or elements of the same
| array or to different functions, or if only one of them is null,
| the results of p<q, p>q, p<=q, and p>=q are unspecified.

It looks like the following program may print either "true" or "false"
regardless of whether the numerical address of "a" is greater than the
numerical address of "b":

#include <iostream>

#define TF(expr) ( (expr) ? "true" : "false" )

int main()
{
int a,b;

std::cout << TF(&b > &a);
std::cout << TF( (long unsigned)&b > (long unsigned)&a );
}

It's possible that this can print two different answers, but the behaviour
is nonetheless well-defined.

--

Frederick Gotham
 
Reply With Quote
 
Frederick Gotham
Guest
Posts: n/a
 
      09-21-2006
Frederick Gotham posted:

> std::cout << TF( (long unsigned)&b > (long unsigned)&a );



Let's assume for the purposes of this discussion that an unsigned long
provides enough bits to store the address of an int.

--

Frederick Gotham
 
Reply With Quote
 
S S
Guest
Posts: n/a
 
      09-22-2006

Kai-Uwe Bux wrote:
> Chris wrote:
>
> > Is there ever a reason to declare this as
> >
> > if(*this == rhs)
> >
> > as opposed to what I normally see
> >
> > if(this == &rhs)
> >
> > ?
> >
> > Seems like the former version is going to be more expensive rather than
> > simply comparing addresses as in the latter (plus the former requires
> > the class to define operator== as well, no?). Wondering if that added
> > effort is ever justified.

>
> I think a reference counted non-intrusive smart pointer could benefit from
> the first version. Consider the following schematic implementation:
>
> template < typename T >
> class refcount_ptr;
>
> template < typename T >
> void swap ( refcount_ptr< T > &, refcount_ptr< T > & );
>
> template < typename T >
> class refcount_ptr {
>
> friend void swap<> ( refcount_ptr<T> &, refcount_ptr<T> & );
>
> struct T_count {
>
> T* t_ptr;
> unsigned long ref_count;
>
> T_count ( T * ptr )
> : t_ptr( ptr )
> , ref_count ( 1 )
> {}
>
> ~T_count ( void ) {
> delete ( t_ptr );
> }
>
> };
>
> T_count * c_ptr;
>
> public:
>
> refcount_ptr ( T * ptr = 0 )
> : c_ptr( new T_count ( ptr ) )
> {}
>
> refcount_ptr ( refcount_ptr const & other )
> : c_ptr ( other.c_ptr )
> {
> ++ c_ptr->ref_count;
> }
>
> ~refcount_ptr ( void ) {
> -- c_ptr->ref_count;
> if ( c_ptr->ref_count == 0 ) {
> delete( c_ptr );
> }
> }
>
> refcount_ptr & operator= ( refcount_ptr const & other ) {
> if ( c_ptr != other.c_ptr ) {
> this->~refcount_ptr();
> new ( this ) refcount_ptr( other );
> }
> return( *this );
> }
>
> T const * operator-> ( void ) const {
> return( c_ptr->t_ptr );
> }
>
> T * operator-> ( void ) {
> return( c_ptr->t_ptr );
> }
>
> // more stuff
>
> };
>
> In this case, the additional cost of the comparison could be zero: the
> refcount_ptr objects fit within registers. It might very well be that
> comparing the values of the c_ptr members is more efficient than comparing
> their addresses. On the other hand, the value comparison will safe on
> hidden self-assignments, which actually could be quite frequent depending
> on the application.
>
>
> Best
>
> Kai-Ue Bux


You mean we have to inherit from this class? If yes, we can hung up
with multiple inheritance!!! and this might not be desirable solution
at all.

-SS

 
Reply With Quote
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      09-22-2006
S S wrote:

>
> Kai-Uwe Bux wrote:
>> Chris wrote:
>>
>> > Is there ever a reason to declare this as
>> >
>> > if(*this == rhs)
>> >
>> > as opposed to what I normally see
>> >
>> > if(this == &rhs)
>> >
>> > ?
>> >
>> > Seems like the former version is going to be more expensive rather than
>> > simply comparing addresses as in the latter (plus the former requires
>> > the class to define operator== as well, no?). Wondering if that added
>> > effort is ever justified.

>>
>> I think a reference counted non-intrusive smart pointer could benefit
>> from the first version. Consider the following schematic implementation:
>>
>> template < typename T >
>> class refcount_ptr;
>>
>> template < typename T >
>> void swap ( refcount_ptr< T > &, refcount_ptr< T > & );
>>
>> template < typename T >
>> class refcount_ptr {
>>
>> friend void swap<> ( refcount_ptr<T> &, refcount_ptr<T> & );
>>
>> struct T_count {
>>
>> T* t_ptr;
>> unsigned long ref_count;
>>
>> T_count ( T * ptr )
>> : t_ptr( ptr )
>> , ref_count ( 1 )
>> {}
>>
>> ~T_count ( void ) {
>> delete ( t_ptr );
>> }
>>
>> };
>>
>> T_count * c_ptr;
>>
>> public:
>>
>> refcount_ptr ( T * ptr = 0 )
>> : c_ptr( new T_count ( ptr ) )
>> {}
>>
>> refcount_ptr ( refcount_ptr const & other )
>> : c_ptr ( other.c_ptr )
>> {
>> ++ c_ptr->ref_count;
>> }
>>
>> ~refcount_ptr ( void ) {
>> -- c_ptr->ref_count;
>> if ( c_ptr->ref_count == 0 ) {
>> delete( c_ptr );
>> }
>> }
>>
>> refcount_ptr & operator= ( refcount_ptr const & other ) {
>> if ( c_ptr != other.c_ptr ) {
>> this->~refcount_ptr();
>> new ( this ) refcount_ptr( other );
>> }
>> return( *this );
>> }
>>
>> T const * operator-> ( void ) const {
>> return( c_ptr->t_ptr );
>> }
>>
>> T * operator-> ( void ) {
>> return( c_ptr->t_ptr );
>> }
>>
>> // more stuff
>>
>> };
>>
>> In this case, the additional cost of the comparison could be zero: the
>> refcount_ptr objects fit within registers. It might very well be that
>> comparing the values of the c_ptr members is more efficient than
>> comparing their addresses. On the other hand, the value comparison will
>> safe on hidden self-assignments, which actually could be quite frequent
>> depending on the application.
>>
>>
>> Best
>>
>> Kai-Ue Bux

>
> You mean we have to inherit from this class?


No. What made you think that?

Note refcount_ptr<T> is just a watered down version of tr1::shared_ptr<T>
for the sake of exposision: It does not feature a custom deleter and I left
out the methods like operator<, operator==, ...; and I also did not support
for making refcount_ptr<D> and refcount_ptr<T> assignment compatible it D*
and T* are. However, the intended use is just like tr1::shared_ptr<T>, in
particular, you are not meant to inherit from refcount_ptr<T>.


> If yes, we can hung up with multiple inheritance!!! and this might not be
> desirable solution at all.


What would be wrong with multiple inheritance?


Best

Kai-Uwe Bux
 
Reply With Quote
 
Noah Roberts
Guest
Posts: n/a
 
      09-22-2006

Frederick Gotham wrote:
> Noah Roberts posted:
>
> > Why would that invoke undefined behavior??

>
> Forgive me, the behaviour is "unspecified" rather than "undefined".


These are very different.

>
> Page 88 of the current Standard:


When quoting the standard it is better to use section numbers instead
of page numbers. It is page 100 of the one I'm looking at right now.
The section you are quoting is 5.9

>
> | If two pointers p and q of the same type point to different objects
> | that are not members of the same object or elements of the same
> | array or to different functions, or if only one of them is null,
> | the results of p<q, p>q, p<=q, and p>=q are unspecified.
>
> It looks like the following program may print either "true" or "false"
> regardless of whether the numerical address of "a" is greater than the
> numerical address of "b":
>
> #include <iostream>
>
> #define TF(expr) ( (expr) ? "true" : "false" )
>
> int main()
> {
> int a,b;
>
> std::cout << TF(&b > &a);
> std::cout << TF( (long unsigned)&b > (long unsigned)&a );
> }
>
> It's possible that this can print two different answers, but the behaviour
> is nonetheless well-defined.


I don't think you are interpreting that paragraph correctly. Placing
your quote into context with the section it is found in you have things
such as the paragraph before the one you quote:

"If two pointers p and q of the same type point to the same object or
function, or both point one past the end of the same array, or are both
null, then p<=q and p>=q both yield true and p<q and p>q both yield
false."

And the one following:

"If two pointers point to non-static data members of the same object,
or to subobjects or array elements of such members, recursively, the
pointer to the later declared member compares greater provided the two
members arenot separated by an access-specifier label (11.1) and
provided their class is not a union."

Both of the two exceptions also have paragraphs dictating exactly how
the comparison will return. Unspecified in the former case, equal in
the later.

With this context in mind "specified" means exactly which value will be
returned by the operation and gives us some pretty clear rules about
the layout of classes and arrays. Because the locations of a and b are
not defined, in our case, the comparison of their address cannot be
specified as has been clearly done with other cases. "Unspecified" in
this case simply means that there is no way of knowing before hand what
the return of that operation will be as there are no rules governing
the relative locations of a and b; it doesn't mean it won't be a valid
comparison which is what your interpretation is.

Your interpretation of "unspecified" leans closer to "undefined"
meaning there is nothing governing what the result will be...that isn't
the case here. We can still assume the camparison is a valid one and
will result in true/false depending on the relative location in memory
of these two objects. "Unspecified" does not indicate otherwise, it
just means the implementation is free to put these objects anywhere it
wants in memory, which is different to such cases when the result is
specified.

 
Reply With Quote
 
Noah Roberts
Guest
Posts: n/a
 
      09-22-2006

Frederick Gotham wrote:
> Noah Roberts posted:
>
> > Why would that invoke undefined behavior??

>
> Forgive me, the behaviour is "unspecified" rather than "undefined".


Thinking about this more I have a hard time understanding why you are
trying to convince me that the comparison you perform in your assert
could create strange and meaningless results. If you believe such is
the case then you should not be using the assert in question at all.
You're just convincing me that in this case I am correct...while you
seem hell bent on proving me wrong

 
Reply With Quote
 
Jerry Coffin
Guest
Posts: n/a
 
      09-22-2006
In article <GpAQg.13975$(E-Mail Removed)>, http://www.velocityreviews.com/forums/(E-Mail Removed)
says...

[ ... ]

> The behaviour is undefined if you compare two pointers which don't point
> into the same array. The following invokes UB:
>
> int array1[5], array2[5], *p1 = array1+3, *p2 = array2+2;
>
> p2 > p1; /* UB! */


As you've already noted, it's unspecified rather than undefined.

More importantly, see 20.3.3/8, and simply use:

bool whatever = std::less(p1,p2);

From a viewpoint of determining whether something involves self-
assignment, we're mostly concerned with the fact that the two pointers
either consistently compare equal or non-equal -- and std::less gives us
that.

--
Later,
Jerry.

The universe is a figment of its own imagination.
 
Reply With Quote
 
Noah Roberts
Guest
Posts: n/a
 
      09-22-2006

Jerry Coffin wrote:
> In article <GpAQg.13975$(E-Mail Removed)>, (E-Mail Removed)
> says...


> From a viewpoint of determining whether something involves self-
> assignment, we're mostly concerned with the fact that the two pointers
> either consistently compare equal or non-equal -- and std::less gives us
> that.


So does the equality operator. If two pointers represent the same
address they compare equal. This of course will be governed by any
necissary conversions to come up with the "composite pointer type."

See 5.10.1

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
POD and assignment operator and test operator Hicham Mouline C++ 2 09-01-2009 06:00 PM
conditions for automatic generation of default ctor, copy ctor,and default assignment operator (operator) puzzlecracker C++ 8 04-15-2008 09:56 PM
Augument assignment versus regular assignment nagy Python 36 07-20-2006 07:24 PM
comma operator and assignment operator G Patel C Programming 4 02-08-2005 02:53 AM
Beanshell - assignment operator not working? Wolfgang Groiss Java 0 11-19-2003 03:56 PM



Advertisments