Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   Re: Can a temporary be assigned to itself? (http://www.velocityreviews.com/forums/t958951-re-can-a-temporary-be-assigned-to-itself.html)

James Kanze 03-22-2013 01:41 PM

Re: Can a temporary be assigned to itself?
 
On Friday, 22 March 2013 09:05:54 UTC, Juha Nieminen wrote:

> If you are implementing the regular operator=() for a class, you (usually)
> need to take into account the special case that the same object is being
> assigned to itself. (If you don't, you may end up deleting the managed
> resource when you shouldn't.)


If you need to take the special case of self-assignment into
account, your operator is probably broken already. Think about
what might happen if you delete something in the object, and
then the acquisition of your resource throws. You end up with
an object with a pointer to a deleted resource.

--
James

Balog Pal 03-22-2013 06:46 PM

Re: Can a temporary be assigned to itself?
 
On 3/22/2013 2:41 PM, James Kanze wrote:
> On Friday, 22 March 2013 09:05:54 UTC, Juha Nieminen wrote:
>
>> If you are implementing the regular operator=() for a class, you (usually)
>> need to take into account the special case that the same object is being
>> assigned to itself. (If you don't, you may end up deleting the managed
>> resource when you shouldn't.)

>
> If you need to take the special case of self-assignment into
> account, your operator is probably broken already. Think about
> what might happen if you delete something in the object, and
> then the acquisition of your resource throws. You end up with
> an object with a pointer to a deleted resource.


I heard that claim a lot, and it sounded good, but I never could really
map it to actual code.

Taking your example, my code would call Dispose() that will call the
proper delete and set the pointer to NULL, then we proceed to allocation
part. Should it fail we're in a proper non-owning state fulfilling the
basic XG.

Sure it it possible to do things in improper order or overlook
something, but that applies to anything in programming. I considered the
suggested alternatives many times then concluded that the (pretty rare)
instances I have providing op= are okay with the self-assignment check
up front and the rest is fine.

IME most classes will have either default or deleted op=, the rest is
maybe 1%. And that small population is mostly primitive library carried
over for decades.

In the cases I reviewed with broken op= or more general rule-of-three
related discrepancy the problem was not with self-assigment or its
strategy but that the actual class should not have t in the first place,
rather pick up a proper member or base class. Well, it coming back now
-- the problem was usually with obtaining something in ctor body, and
leaked due to dtor not called. And fixing that the proper way, using a
proper controller for the resource made the op= gone for good as bonus
side effect. :)




Tiib 03-22-2013 07:52 PM

Re: Can a temporary be assigned to itself?
 
On Friday, 22 March 2013 20:46:59 UTC+2, Balog Pal wrote:
> On 3/22/2013 2:41 PM, James Kanze wrote:
> > On Friday, 22 March 2013 09:05:54 UTC, Juha Nieminen wrote:
> >
> >> If you are implementing the regular operator=() for a class, you (usually)
> >> need to take into account the special case that the same object is being
> >> assigned to itself. (If you don't, you may end up deleting the managed
> >> resource when you shouldn't.)

> >
> > If you need to take the special case of self-assignment into
> > account, your operator is probably broken already. Think about
> > what might happen if you delete something in the object, and
> > then the acquisition of your resource throws. You end up with
> > an object with a pointer to a deleted resource.

>
> I heard that claim a lot, and it sounded good, but I never could really
> map it to actual code.


Object should remain in sane state if anything throws exceptions
during assignment. Sole imaginable sane state is "like it was before".

On my case it seems that achieving that has also achieved that the
self-assignment checks are not needed anymore.

[...]

> IME most classes will have either default or deleted op=, the rest is
> maybe 1%. And that small population is mostly primitive library carried
> over for decades.


Interesting.

Domains and applications certainly differ. IME most classes are not
polymorphic. It is efficient to put most such things into vector
(or deque) or used as direct data members of other non-polymorphic
classes.

Lot of non-polymorphic classes may have constant or reference or
unique_ptr or auto_ptr or boost::scoped_ptr or naked pointer
non-static members. These classes should be made explicitly copyable
or movable if one wants them to be in vector or deque or the like.


James Kanze 03-22-2013 08:11 PM

Re: Can a temporary be assigned to itself?
 
On Friday, 22 March 2013 18:46:59 UTC, Balog Pal wrote:
> On 3/22/2013 2:41 PM, James Kanze wrote:
> > On Friday, 22 March 2013 09:05:54 UTC, Juha Nieminen wrote:


> >> If you are implementing the regular operator=() for a class, you (usually)
> >> need to take into account the special case that the same object is being
> >> assigned to itself. (If you don't, you may end up deleting the managed
> >> resource when you shouldn't.)


> > If you need to take the special case of self-assignment into
> > account, your operator is probably broken already. Think about
> > what might happen if you delete something in the object, and
> > then the acquisition of your resource throws. You end up with
> > an object with a pointer to a deleted resource.


> I heard that claim a lot, and it sounded good, but I never could really
> map it to actual code.


> Taking your example, my code would call Dispose() that will call the
> proper delete and set the pointer to NULL, then we proceed to allocation
> part. Should it fail we're in a proper non-owning state fulfilling the
> basic XG.


That's doing things the hard way. As a general rule, you should
construct all of the new values before you start tearing down
anything.

--
James

Balog Pal 03-22-2013 08:24 PM

Re: Can a temporary be assigned to itself?
 
On 3/22/2013 8:52 PM, Tiib wrote:

> Object should remain in sane state if anything throws exceptions
> during assignment. Sole imaginable sane state is "like it was before".


That is strong XG, can be done too at about the same amount of code but
some increased resource cost at runtime. I don't agree that strong XG is
the only sane way but that is up to opinion in general -- and detailed
design at a particular instance, so we should not debate it. :)
....
> Lot of non-polymorphic classes may have constant or reference or
> unique_ptr or auto_ptr or boost::scoped_ptr or naked pointer
> non-static members. These classes should be made explicitly copyable
> or movable if one wants them to be in vector or deque or the like.


I have a full suite of smart pointers: NC, DC, transfer and shared,
certainly if I want a copyable object I use a the DC variant over
anything else. IMO same applies to any resource handler. (btw the said
pointers are policy-based so it's easy to use them for any kind of
resource; I recall a few times using fake-copy that was okay for the
case).

IME starting to hand-craft an op= is the last resort and is a ticked for
more easy-to-break maintenance too.




Balog Pal 03-22-2013 08:51 PM

Re: Can a temporary be assigned to itself?
 
On 3/22/2013 9:11 PM, James Kanze wrote:
>> Taking your example, my code would call Dispose() that will call the
>> proper delete and set the pointer to NULL, then we proceed to allocation
>> part. Should it fail we're in a proper non-owning state fulfilling the
>> basic XG.

>
> That's doing things the hard way. As a general rule, you should
> construct all of the new values before you start tearing down
> anything.


That's also a fair approach if having both new and old around is not
considered risk for resource overuse.

IMO that general rule applies to complex situations, mostly in the
application realm -- way less in the basic primitives that just manage a
single resource or memory block.

When I say

String a("a");
a = "ab";
and the latter fails with memory error I honestly see no value to make
it strong XG, and keep original value.

I tried to figure out what std::string is supposed to do here but choked
;-)

But my point is not really the how, but that it IMO it can be reasonably
expected to be done correctly in those rare cases, and if this is a
problem for someone I can't imagine how he can deal with something less
trivial.


Tiib 03-23-2013 11:24 AM

Re: Can a temporary be assigned to itself?
 
On Friday, 22 March 2013 22:24:59 UTC+2, Balog Pal wrote:
> On 3/22/2013 8:52 PM, Tiib wrote:
> > Object should remain in sane state if anything throws exceptions
> > during assignment. Sole imaginable sane state is "like it was before".

>
> That is strong XG, can be done too at about the same amount of code but
> some increased resource cost at runtime. I don't agree that strong XG is
> the only sane way but that is up to opinion in general -- and detailed
> design at a particular instance, so we should not debate it. :)


I did not want to debate it. I have had bad experience with assignment
damaging things. Since '=' is so innocent in code I feel it should be
robust. Common case ... some GUI designer made it too permissive
and user can do illegal copy or move. Throwing is fine since it is
defect of GUI ... however being broken afterwards is out of question.

Strong exception safety guarantee is not needed in lot of other cases.

> > Lot of non-polymorphic classes may have constant or reference or
> > unique_ptr or auto_ptr or boost::scoped_ptr or naked pointer
> > non-static members. These classes should be made explicitly copyable
> > or movable if one wants them to be in vector or deque or the like.

>
> I have a full suite of smart pointers: NC, DC, transfer and shared,
> certainly if I want a copyable object I use a the DC variant over
> anything else.


Reference or constant members you avoid? shared_ptr member is quite
common. Sometimes deep copy sometimes shared copy is needed
when copying an object with such member. Your DC pointer is
interesting. Does it have non-owning side-kick or do you use raw pointer
instead? Transfer and non-copyable ... isn't it unique_ptr?

> IMO same applies to any resource handler. (btw the said
> pointers are policy-based so it's easy to use them for any kind of
> resource; I recall a few times using fake-copy that was okay for the
> case).


I avoid allowing assignment or copying of resources like threads, files or
sockets with just '=' character ... being laconic here is hiding the cost
tag that certainly matters. Moving is better since it is cheaper.

> IME starting to hand-craft an op= is the last resort and is a ticked for
> more easy-to-break maintenance too.


It is important to make novice to realize that compiler will create the
things itself if it only can and that compiler does not always
understand his intentions. If novice does not know that issue with
classes in C++ then he is doomed to write broken classes. Everybody
have seen copyable singletons I trust? Hiding that part of C++ does
not work it feels.

Note that implicit assignment operators do not even offer the
basic exception safety guarantee on lot of cases. So either everything
is nothrow during assignment or you *have* to hand-craft them.


88888 Dihedral 03-24-2013 12:32 AM

Re: Can a temporary be assigned to itself?
 
Öö Tiib於 2013年3月23日星期*UTC+8下午7時24分51秒 寫道:
> On Friday, 22 March 2013 22:24:59 UTC+2, Balog Pal wrote:
>
> > On 3/22/2013 8:52 PM, Öö Tiib wrote:

>
> > > Object should remain in sane state if anything throws exceptions

>
> > > during assignment. Sole imaginable sane state is "like it was before"..

>
> >

>
> > That is strong XG, can be done too at about the same amount of code but

>
> > some increased resource cost at runtime. I don't agree that strong XG is

>
> > the only sane way but that is up to opinion in general -- and detailed

>
> > design at a particular instance, so we should not debate it. :)

>
>
>
> I did not want to debate it. I have had bad experience with assignment
>
> damaging things. Since '=' is so innocent in code I feel it should be
>
> robust. Common case ... some GUI designer made it too permissive
>
> and user can do illegal copy or move. Throwing is fine since it is
>
> defect of GUI ... however being broken afterwards is out of question.
>
>
>
> Strong exception safety guarantee is not needed in lot of other cases.
>
>
>
> > > Lot of non-polymorphic classes may have constant or reference or

>
> > > unique_ptr or auto_ptr or boost::scoped_ptr or naked pointer

>
> > > non-static members. These classes should be made explicitly copyable

>
> > > or movable if one wants them to be in vector or deque or the like.

>
> >

>
> > I have a full suite of smart pointers: NC, DC, transfer and shared,

>
> > certainly if I want a copyable object I use a the DC variant over

>
> > anything else.

>
>
>
> Reference or constant members you avoid? shared_ptr member is quite
>
> common. Sometimes deep copy sometimes shared copy is needed
>
> when copying an object with such member. Your DC pointer is
>
> interesting. Does it have non-owning side-kick or do you use raw pointer
>
> instead? Transfer and non-copyable ... isn't it unique_ptr?
>
>
>
> > IMO same applies to any resource handler. (btw the said

>
> > pointers are policy-based so it's easy to use them for any kind of

>
> > resource; I recall a few times using fake-copy that was okay for the

>
> > case).

>
>
>
> I avoid allowing assignment or copying of resources like threads, files or
>
> sockets with just '=' character ... being laconic here is hiding the cost
>

Are you building some class families which do operator
overloading without carefully investigating the closure
problem of any operation result involved?



Balog Pal 03-24-2013 11:44 AM

Re: Can a temporary be assigned to itself?
 
On 3/23/2013 12:24 PM, Tiib wrote:
> I have had bad experience with assignment
> damaging things. Since '=' is so innocent in code I feel it should be
> robust.


I can understand that. In the early days I also had many problems
related to op=. Then we learned the rule of three. Then we learned RAII,
and sticking to that resulted elimination of hand-crafted op= and cctor
from user code. From there I recall no problems worth mentioning.

If I see an op= in code, my first reaction is to ask a ton of questions
why is it there, and likely result is to send the whole class to design
table. For good. :) In fewer cases it is just cut with slight
modifications. In the remaining rare cases it gets a very thorough
review considering all kind of scenarions, including self-assignment and
exceptions at any point.

>> I have a full suite of smart pointers: NC, DC, transfer and shared,
>> certainly if I want a copyable object I use a the DC variant over
>> anything else.

>
> Reference or constant members you avoid?


I'm not avoiding them, but they're pretty rare turn turn up. And I can't
recall a single case they would trigger special ops -- the natural
consequence is a sensible default cctor and a deleted op=, that is fine
for me. If I wrote them by hand the copy would not be "equivalent" to
the original, and I guess that would surprise someone later on.

> shared_ptr member is quite common.


Not in my work. But I see no problem with it -- if it's used for
sharing, then it will apply for its container just by doing nothing. (Or
the container deletes the copy possibility and just uses it as a NC
holder for other conveniences -- my NC pointer uses CHECKED_DELETE,
shared_ptr is smarter than that.)

> Sometimes deep copy sometimes shared copy is needed
> when copying an object with such member.


IMO it's rarther either shared or NC. If I want DC, why pick the
shared_ptr over DC in the first place?

> Your DC pointer is
> interesting. Does it have non-owning side-kick or do you use raw pointer
> instead? Transfer and non-copyable ... isn't it unique_ptr?


'Transfer' is the plain old auto_ptr, replaced by unique_ptr these days.
NC would have been boost::scoped_ptr, but it turned out to have crippled
interface, so I made mine using auto_ptr's interface (I like the
reset/release a lot, and need get regularly dealing with C-interfaced
other components), just stripped cctor, op=, the templated ctors (mostly
out of fear) and the deleter comes from policy. In some environments it
got an extra member to allow external init (do reset() and provide &ptr
to be assigned) where such approach to create new objects is common.

>> IMO same applies to any resource handler. (btw the said
>> pointers are policy-based so it's easy to use them for any kind of
>> resource; I recall a few times using fake-copy that was okay for the
>> case).

>
> I avoid allowing assignment or copying of resources like threads, files or
> sockets with just '=' character ... being laconic here is hiding the cost
> tag that certainly matters. Moving is better since it is cheaper.


I used all of those only for NC. Certainly move would make sense, but
the compilers I use did not yet pick up move semantics properly,
eventually I'll switch to more of that.

>> IME starting to hand-craft an op= is the last resort and is a ticked for
>> more easy-to-break maintenance too.

>
> It is important to make novice to realize that compiler will create the
> things itself if it only can and that compiler does not always
> understand his intentions.


Rule of 3 covers that, and certainly a novice shall never gain check-in
rights before mastering that (along with rest of EC++3rd)...

> If novice does not know that issue with
> classes in C++ then he is doomed to write broken classes. Everybody
> have seen copyable singletons I trust? Hiding that part of C++ does
> not work it feels.


.... but knowing those details do not map directly to design and coding,
there's way more. And broken classes are supposed to be caught on
review. sure, novices are doomed to write a ton of them before gaining
wisdom to get it right on the first attempt. and with strict meaning of
'broken' I guess even veterans fail with the first attempt more often
than not. ;-)))

IRL we fight program complexity on a broader level, that usually imposes
restrictions on how objects are created, held, disposed of; implicit
responsibilities for some actions, forbidding some other activity (like
storing pointers/refs to a thing you can't prove to live long enough).

> Note that implicit assignment operators do not even offer the
> basic exception safety guarantee on lot of cases.


They do memberwise assignment, that I recall was fine for all my value
classes. I try to imagine a broken situation, but the only scenario
jumps to mind is when I have a group of members that shall be in synch
and one may throw on copy -- my first question would be "how come that
group is not a class in its own right?"

> So either everything
> is nothrow during assignment or you *have* to hand-craft them.


IMO we're lightyears from that.



Tiib 03-24-2013 01:58 PM

Re: Can a temporary be assigned to itself?
 
On Sunday, 24 March 2013 13:44:19 UTC+2, Balog Pal wrote:
> On 3/23/2013 12:24 PM, Tiib wrote:
> > Reference or constant members you avoid?

>
> I'm not avoiding them, but they're pretty rare turn turn up. And I can't
> recall a single case they would trigger special ops -- the natural
> consequence is a sensible default cctor and a deleted op=, that is fine
> for me. If I wrote them by hand the copy would not be "equivalent" to
> the original, and I guess that would surprise someone later on.


Yes, copyability is less common than language designer originally
thought IMO ... but movability is more usual. Constants are quite
common members. It is quite frequently suggested to use immutability
wherever it makes sense.

Reference is very close to constant not-null pointer. I often have
references in components to track relation back to composite. If
moving components around makes sense (not often) then there is
assignment needed. Such assignment can assert that the composite
references are already equal or throw logic_error if they aren't
because assigning components of different composite does not make
sense.

....
> > Sometimes deep copy sometimes shared copy is needed
> > when copying an object with such member.

>
> IMO it's rarther either shared or NC. If I want DC, why pick the
> shared_ptr over DC in the first place?


Because shared_ptr has handy non-owning (but tracking) partner. I need to
think how to make similar thing to deep copy pointer. I already asked it:

> > Your DC pointer is
> > interesting. Does it have non-owning side-kick or do you use raw pointer
> > instead?


....
> IRL we fight program complexity on a broader level, that usually imposes
> restrictions on how objects are created, held, disposed of; implicit
> responsibilities for some actions, forbidding some other activity (like
> storing pointers/refs to a thing you can't prove to live long enough).


An object that stores pointer has to have ability to track the lifetime
of pointed at object, simplest case is when the life time of two objects
is bound (either way), reference count is powerful way to track, as are
various signaling and observing systems.

> > Note that implicit assignment operators do not even offer the
> > basic exception safety guarantee on lot of cases.

>
> They do memberwise assignment, that I recall was fine for all my value
> classes. I try to imagine a broken situation, but the only scenario
> jumps to mind is when I have a group of members that shall be in synch
> and one may throw on copy -- my first question would be "how come that
> group is not a class in its own right?"


It is. It is such "group" whose members are interrelated that we are
usually talking about when talking about classes. Lot of combinations of
values of members of classes are usually invalid. So now we talk
about copy-assignment and move-assignment of such groups. Half assignment
can end with invalid combination.

> > So either everything
> > is nothrow during assignment or you *have* to hand-craft them.

>
> IMO we're lightyears from that.


We are ligtyears from everything being nothrow during copy-assignment,
with move-assignment we are commonly there.


All times are GMT. The time now is 08:09 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.