Re: [boost] Re: SmartPtr - Exception safety reprise
On Thursday, February 06, 2003 3:13 PM [GMT+1=CET], David B. Held [EMAIL PROTECTED] wrote: David B. Held [EMAIL PROTECTED] wrote in message b1m57m$702$[EMAIL PROTECTED]">news:b1m57m$702$[EMAIL PROTECTED]... [...] I mean, the optimally_inherit eliminates the empty bases, and yet there is size bloat. So VC++ makes the class bigger for some other reason than that it has empty bases. I will try to write some tests to see why that is, or at least how. I repeat, I bet it's MI-related. The proof of the pudding is in the eating. I got a chance to taste the pudding, the the results are inconclusive. The cause of the size bloat was that I had changed ref_counted to inherit from noncopyable. Seems like an innocent enough change. Seems that for the single-inheritance case, we should see some EBO action, right? Well, we do, unless ref_counted is a base in an MI hierarchy. Why its place in an hierarchy should change its size is a mystery to me, What do you mean that its *place* in the hierarchy affects the size? If it's in the hierarchy, it's a base. but taking out noncopyable restores that magical size. Now, I would appreciate it if people with Intel, CW, and some other compilers would try out the code in the sandbox and see if the first test passes (turn on --log-level=all, and pipe the output to your favorite paginator). BTW, these are not the kind of tests I was thinking of. I was more interested in simple tests with SI and MI using dummy classes with zero or more data members and trivial/non-trivial ctors/dtors. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: SmartPtr - Exception safety reprise
From: David B. Held [EMAIL PROTECTED] Dave Abrahams [EMAIL PROTECTED] wrote in message 008c01c2ce1f$87ca8620$6501a8c0@penguin">news:008c01c2ce1f$87ca8620$6501a8c0@penguin... [...] What do you mean that its *place* in the hierarchy affects the size? If it's in the hierarchy, it's a base. Sorry, I thought that it is noncopyable, not ref_counted. But if it's not in the smart_ptr hierarchy, it's not a base. So if it's not a base, it's at the top (or bottom) of the hierarchy, with noncopyable as a base. And that's my point. Being a base changes its size. No, it doesn't. It can't. sizeof(ref_counted) is the same no matter where you measure it. What changes is the size that gets contributed to its derived class. It's clear to me why that could happen. It could be just a simple-minded rule to avoid violating the standard requirements, which are written so that no two objects of the same type can have the same address. The rule would be, if I applied the EBO on this type, add some padding after it in an MI context so that other bases of the same type can't end up overlapping with it. It's a dumb rule, since it's easy enough to lay out empty bases in the single-inheritance case at the beginning of the object, and since all types have size 0, you don't need to do anything other than not optimize in the MI case. BTW, these are not the kind of tests I was thinking of. I was more interested in simple tests with SI and MI using dummy classes with zero or more data members and trivial/non-trivial ctors/dtors. Yes, like what Jason Shirk did. It's just that I did a diff of the version that was the right size and the one that wasn't, and saw that change, so I wanted to test it right away. The weird thing is, the storage policy also has an empty base for the policy adaptor, and yet, it doesn't seem to affect the size of smart_ptr. Go figure. But like Jason also pointed out, the order of bases makes a difference, so maybe the fact that storage_policy comes first affects the size. I noticed that this is actually the case on bcc, and I suspect, on most compilers. Anyway, non-copyable doesn't really convey the right concept anyway, since ref_counted defines copy c'tors! I just wanted to hide the assignment operator, and doing that manually works fine. I'm interested in what happens when either of ownership or storage are themselves empty. And, of course, the independent tests not based on smart_ptr. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: SmartPtr - Exception safety reprise
David B. Held [EMAIL PROTECTED] writes: David Abrahams [EMAIL PROTECTED] wrote in message [EMAIL PROTECTED]">news:[EMAIL PROTECTED]... [...] The problem arises if the user passes an empty policy class with non-trivial ctor or dtor: then the fact that it's being constructed/destructed at different times from the rest of the bases will have visible effects. Ok, now I see the problem, and one conceivable scenario for this is an intrusive ownership policy. It would most likely be empty, yet the cleanup would occur in the d'tor under my latest model, so that it has proper exception safety. Ouch. On the other hand, I just saw a reference to Josuttis Vandevoorde that I recalled reading whereby they refer to a BaseAndMember idiom in which they aggregate the non-empty parameter and derive from the emtpy one, relying on EBO to give optimal size. That's called boost::compressed_pair. Once again, I might be able to reverse the logic and aggregate the empty member and derive from the non- empty one. I guess that depends on how well VC++ friends perform empty member optimization. There is no such thing as empty member optimization. That's true, but we're no longer talking about EBO failure. Even after the empty bases have been eliminated, we still get bloating. So it's just random size adjustment. But you're right that some testing might increase the confidence that the size won't go up. I bet you it's not random, but associated with MI. [...] It would be nice to have some assurance that this won't happen, but the current state of affairs with the MI setup doesn't exactly involve EBO I don't know what you mean by that. I mean, the optimally_inherit eliminates the empty bases, and yet there is size bloat. So VC++ makes the class bigger for some other reason than that it has empty bases. I will try to write some tests to see why that is, or at least how. I repeat, I bet it's MI-related. -- David Abrahams [EMAIL PROTECTED] * http://www.boost-consulting.com Boost support, enhancements, training, and commercial distribution ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
RE: [boost] Re: SmartPtr - Exception safety reprise
-Original Message- From: David Abrahams [mailto:[EMAIL PROTECTED]] David B. Held [EMAIL PROTECTED] writes: Well, I want to at least give the VC++ guys a few days to see if they say anything. I posted a question on a M$ newsgroup. I think I did the first time around, too, and they didn't. It would be really cool if, say, Jason Shirk offered some insight, or at least knocked some skulls so we got *some* kind of answer, even if it's there's no way in heck we will give out that kind of information. If you aren't getting reasonably prompt responses to questions like this on MS newsgroups, send me a private email and I'll definitely follow up. As a team, VC++ is significantly more responsive to NG posts now, but some still slip through the cracks. What question are you asking? I think all NDAs on the vc7.1 betas are expired, so I can just run a test... However, you obviously missed my point: there _is_ no way in heck they're going to change the object layout, thus making vc7.1 object code incompatible with vc7 object code. Objects with multiple empty bases have to have the same size in both versions and their members have to live at the same offsets. BTW, VC++ is not the only kid on the block, and the same argument applies to all the other players. As usual, you are absolutely correct. Backwards compatibility in our object model is critical. I seriously doubt we'll ever do the ZBO by default. I do plan on implementing it in the next few months, and it will definitely be under a switch. I can't possibly predict when anyone outside MS will see such a compiler though, sorry. -- Jason Shirk VC++ Compiler Team ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: SmartPtr - Exception safety reprise
David B. Held [EMAIL PROTECTED] writes: Well, I want to at least give the VC++ guys a few days to see if they say anything. I posted a question on a M$ newsgroup. I think I did the first time around, too, and they didn't. It would be really cool if, say, Jason Shirk offered some insight, or at least knocked some skulls so we got *some* kind of answer, even if it's there's no way in heck we will give out that kind of information. What question are you asking? I think all NDAs on the vc7.1 betas are expired, so I can just run a test... However, you obviously missed my point: there _is_ no way in heck they're going to change the object layout, thus making vc7.1 object code incompatible with vc7 object code. Objects with multiple empty bases have to have the same size in both versions and their members have to live at the same offsets. BTW, VC++ is not the only kid on the block, and the same argument applies to all the other players. At least then I could give up hope, and we could fully enter the tedious debate over alternatives. But there must be *someone* on the VC++ compiler team that wrote the EBO code, and if it were me, I'd have enough pride to at least say when I know that it *does* work (and it does work for some MI...optimally_inherit was doing its job until the latest round of changes). What is optimally_inherit? Latest round of changes in what? -- David Abrahams [EMAIL PROTECTED] * http://www.boost-consulting.com Boost support, enhancements, training, and commercial distribution ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: SmartPtr - Exception safety reprise
David B. Held [EMAIL PROTECTED] writes: David Abrahams [EMAIL PROTECTED] wrote in message [EMAIL PROTECTED]">news:[EMAIL PROTECTED]... [...] C) Make sure the first base class of smart_ptr is the one that manages destruction of its resources: snip I was actually thinking in this direction somewhat. Then you're getting the hang of this EH stuff; congratulations! I did notice that it really is the smart_ptr d'tor that really knows how to properly clean stuff up, and it should probably be the one to do so. But coordinating cleanup in the smart_ptr dtor was causing the problem you cited in the first place! In my version it's the ptr_manager base class that coordinates the cleanup by encapsulating ownership and storage. -Dave -- David Abrahams [EMAIL PROTECTED] * http://www.boost-consulting.com Boost support, enhancements, training, and commercial distribution ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: SmartPtr - Exception safety reprise
David B. Held [EMAIL PROTECTED] writes: David Abrahams [EMAIL PROTECTED] wrote in message [EMAIL PROTECTED]">news:[EMAIL PROTECTED]... [...] What question are you asking? I think all NDAs on the vc7.1 betas are expired, so I can just run a test... Actually, I wanted someone on the compiler team to give me a set of circumstances under which EBO is guaranteed to work. If there is no way to get MI to fit into those circumstances, then we can give up. [...] BTW, VC++ is not the only kid on the block, and the same argument applies to all the other players. Yes, but you seem to imply that other Win32 compilers try to be object-compatible with VC++ Up to a point. I know MWerks is object-compatible in the single-inheritance case (for the sake of COM and MFC), but not if there's MI. However, they still have MI EBO problem. Further, this is not a Win32-specific problem. Most Unix compilers that aren't GCC-3.x have it as well, AFAICT. so it seems they should exhibit the same behaviour. If there is some way to get the desired optimization, with any luck, the other compilers will perform it as well. Or maybe this is wishful thinking? It is in the case of MWerks, anyway. [...] What is optimally_inherit? Latest round of changes in what? Optimally_inherit is a device that is the dual of compressed_pair. Andrei suggested it when this issue first came up. Whilst compressed_pair aggregates when a type is non-empty, and inherits when it's empty, optimally_inherit inherits when the type is non-empty, and just calls c'tors on temporaries when the type is empty. This way, empty bases don't actually enter the inheritance tree. I guess that's OK if you don't care how many ctors and dtors get called. The lifetimes of these temporaries obviously won't mirror that of the smart_ptr. Sounds like a fragile arrangement to me. Unfortunately, EBO interacts with non-empty bases as well as empty ones, and that is our problem. If you only inherit from non-empty bases, how is EBO relevant at all? The latest round of changes is the set of changes that moves cleanup from named procedures (destroy(), release(), etc.) to d'tors. For this reason, I suspected that non-trivial user-defined d'tors were causing VC++ to drop EBO. But commenting out the d'tors just to check the size did not restore EBO. So now I would like a VC++ compiler team member (preferably the one(s) who wrote the EBO code) to tell me when EBO works, and when it doesn't, or as much about that as possible. The optimally_inherit trick works just fine on BCB, and gcc didn't need it to begin with (that big stud of a compiler!). If we can get VC++ and VC++ wannabes to invoke EBO again, we can at least cover a good amount of the market, no? Yes. I know that optimally_inherit *does* work under VC++ for some cases. I just don't know exactly what those cases are, and I don't really want to spend a week trying to discover it, especially as that won't help people who are writing custom policies. Why not? -- David Abrahams [EMAIL PROTECTED] * http://www.boost-consulting.com Boost support, enhancements, training, and commercial distribution ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: SmartPtr - Exception safety reprise
David B. Held [EMAIL PROTECTED] writes: David Abrahams [EMAIL PROTECTED] wrote in message [EMAIL PROTECTED]">news:[EMAIL PROTECTED]... [...] Up to a point. I know MWerks is object-compatible in the single-inheritance case (for the sake of COM and MFC), but not if there's MI. However, they still have MI EBO problem. Further, this is not a Win32-specific problem. Most Unix compilers that aren't GCC-3.x have it as well, AFAICT. So in your opinion, *ought* the optimally_inherit solution to work even on these compilers? If you don't care about ctors and dtors, it sounds plausible, but there's no reason in principle that they shouldn't have the same problems you cite below for VC++. You never know with some of them, though. Borland is particularly strange about layout. [...] I guess that's OK if you don't care how many ctors and dtors get called. The lifetimes of these temporaries obviously won't mirror that of the smart_ptr. Sounds like a fragile arrangement to me. I imagine that the temporaries won't get created at all, Whaaa? A temporary that never gets created? since their sole purpose is to verify policy compatibility. In the majority of cases, they will simply call an appropriate copy c'tor, which will be trivial or generated, because the class has no state. Maybe you should illustrate what you mean, 'cause I'm lost. If you only inherit from non-empty bases, how is EBO relevant at all? That's a very good question. Maybe I should call it an Empty Derived Optimization problem. For some reason, even in this configuration, VC++ insists that sizeof(smart_ptr) 8: class smart_ptr : optimally_inherit optimally_inheritstorage, checking, optimally_inheritownership, conversion { ... } Since I can't see what's in the bases nor any of smart_ptr's data members here, it's hard to know how to interpret sizeof(smart_ptr) 8 or whether it's even a problem [but I get it below]. I can prove that optimally_inheritstorage, checking only derives from storage, and similarly for ownership with a simple test case. So why VC++ thinks it needs to inflate the size of smart_ptr is beyond me. But it isn't just smart_ptr. It inflates the size of the top- level optimally_inherit, which is inheriting from two non-empty base classes. Perhaps we should call it the Non-emtpy Base MI Pessimization (NoBMIP)? OK, I get the picture now. I assumed it was because it didn't want any of the bases to share an address with the derived class, which is analogous to the EBO case. But perhaps I misunderstand what is going on, and you can shed some light on it for me. I don't think I can do any better than you. I have the same tools at my disposal. I'd do a bunch of experiments and look at the resulting class layouts by checking the size and the relative addresses of members. [...] I know that optimally_inherit *does* work under VC++ for some cases. I just don't know exactly what those cases are, and I don't really want to spend a week trying to discover it, especially as that won't help people who are writing custom policies. Why not? Well, suppose that I discover *some* configuration in which EBO and optimally_inherit produce the desired size, but I don't know *why* that configuration has the desired result. How is a user to know if his custom policy is going to kill EBO again or not, based on the working configuration? You could probably figure out the VC++ algorithm by experimentation, but that still wouldn't help a user trying to write portable, efficient code, unless you find a workaround for every other compiler. -- David Abrahams [EMAIL PROTECTED] * http://www.boost-consulting.com Boost support, enhancements, training, and commercial distribution ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost