- About virtual inheritance - 11 Updates
- Struggling with bind syntax - 8 Updates
- Struggling with bind syntax - 1 Update
- braced-init-list form of a condition - 2 Updates
- direct-initialization - 1 Update
- Design flaws (Scott..) - 1 Update
"Öö Tiib" <ootiib@hot.ee>: Jun 30 11:46PM -0700 On Tuesday, 30 June 2015 18:26:33 UTC+3, Martijn van Buul wrote: > is "more efficient" or not. I once rewrote a framework that used shared_ptr > to intrusive_ptr, because it allowed me to avoid using new. The resulting > gain in speed (and reduced memory fragmentation) was significant. Where you need 'new' with 'shared_ptr'? That was the whole point of my question ... to find motivating examples. > Note that I'm not saying that intrusive_ptr is generally better than > shared_ptr. It's not, but sometimes intrusive_ptr works where shared_ptr > doesn't. May be. I have zero good examples. I can understand someone saying that 'shared_ptr' has unneeded features for him (like indirection to deleter or weak count) but in evolving project it is hard to tell if those will be needed or not. > The same can be said for most of the *intrusive part of Boost. Intrusive containers in boost are certainly great but these can not cause diamonds since the hooks can be bases or members. |
"Öö Tiib" <ootiib@hot.ee>: Jun 30 11:58PM -0700 On Wednesday, 1 July 2015 09:47:03 UTC+3, Öö Tiib wrote: > > The same can be said for most of the *intrusive part of Boost. > Intrusive containers in boost are certainly great but these can > not cause diamonds since the hooks can be bases or members. Just a clarification so people who read it won't get confused. Boost isn't monolithic blob and 'boost::intrusive_ptr' is part of "Boost Smart Ptr" library not part of "Boost Intrusive" library. So the trees and containers are in separate libraries from that ptr. |
Juha Nieminen <nospam@thanks.invalid>: Jul 01 08:05AM > instead of intrusive refcounting. I always suggested it but did not have > clear examples why. Here 'std::make_shared' seems both simpler and > more efficient. I don't understand how you conclude that shared_ptr is more efficient in this case. Why would it be? The major problem with shared_ptr is that it needs to make an additional allocation to contain all of its ancillary data, and dynamic allocation is inefficient. With an intrusive smart pointer you don't need the extra allocation. In practice you will *never* need to multiple-inherit from two classes that use an intrusive smart pointer scheme. (Heck, I don't even remember when was the last time I needed to use smart pointers at all.) It was just an illustrative example of when virtual inheritance could be potentially useful. --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
Bo Persson <bop@gmb.dk>: Jul 01 10:30AM +0200 On 2015-07-01 10:05, Juha Nieminen wrote: > allocation to contain all of its ancillary data, and dynamic allocation > is inefficient. With an intrusive smart pointer you don't need the > extra allocation. std::make_shared is allowed/supposed to allocate a single memory block large enough to hold both the pointed-to data and its internal info. If it does, that would be just as efficient as an intrusive pointer, without being that 'intrusive'. Bo Persson |
Martijn van Buul <pino@dohd.org>: Jul 01 10:22AM * Öö Tiib: >> gain in speed (and reduced memory fragmentation) was significant. > Where you need 'new' with 'shared_ptr'? That was the whole point of my > question ... to find motivating examples. smart_ptr uses 'new' internally (and the boost implementation used it twice as much) - which caused performance issues. The problem at hand revolved around a variant[1] of boost::any. boost::any has performance issues, because it relies on dynamic allocation. cdiggins::any works around this by including a memory buffer to be used for small objects (like integers, doubles, small POD classes and structs) using in-place new. This greatly reduces the burden on the heap, especially if you add an operator new() and operator delete() that will manage instances if cdiggins::any in a separate pool. Before you dismiss this as premature optimalisation: It wasn't. It reduced runtime *of the entire system* by almost 20% and reduced memory requirements by a similar number due to a reduce in memory fragmentation. shared_ptr<> throws a spanner into the works, however. Alongside the held object, it needs to include at least a reference counter. It cannot combine the held object and the counter in a single object using composition, as it must be possible to create a shared_ptr<> from a naked pointer. It must therefore internally use a template class that contains a "naked" pointer to the held object, alongside the reference count. This means that the overloaded operator new() of cdiggins::any will still be used, at the expense of an extra allocation of the internal template class on the heap. This, however, is exactly the issue we were trying to address using cdiggins::any: The heap usage is back (thus increasing runtime and increasing fragmentation). make_shared() tries to work around this by allocating one block of memory for both, but then you're back at not using the overloaded operator new. Neither can be fixed, without intimate knowledge of the implementation. intrusive_ptr turned out to be the saving grace, however: 1) the overloaded operator new() and delete() continue to function. 2) No extra objects will be allocated on the heap, as no internal reference counting object is required. 3) It is a solution that does not depend on implementation details of shared_ptr There is a price to pay: Reduced functionality (no support for anything resembling std::weak_ptr), and added complexity - either deriving from a base class (which opens up the diamond pattern issue) or adding accounting functions to the containing namespace. For our application, this was well worth it. Again, I'm not saying intrusive_ptr<> is the universal solution, and I don't use them unless profiling indicates that I should. However, I have enough evidence to dispel blanket statements like "shared_ptr is more efficient". Blanket statements are always wrong. I never make them :P. Martijn [1] See http://www.drdobbs.com/an-efficient-variant-type/184402027 -- Martijn van Buul - pino@dohd.org |
"Öö Tiib" <ootiib@hot.ee>: Jul 01 03:27AM -0700 On Wednesday, 1 July 2015 11:05:14 UTC+3, Juha Nieminen wrote: > > more efficient. > I don't understand how you conclude that shared_ptr is more efficient > in this case. Why would it be? It loses all the need for additional burden that virtual inheritance and diamond causes. > allocation to contain all of its ancillary data, and dynamic allocation > is inefficient. With an intrusive smart pointer you don't need the > extra allocation. I did write 'std::make_shared'. That does one allocation and puts the ref-count block adjacent to object in memory. > In practice you will *never* need to multiple-inherit from two classes > that use an intrusive smart pointer scheme. It was the whole question. Where I see a virtual base then I am always very interested that maybe it is now the case where it gains performance, clarity or convenience. However it typically performs worse, the relations are mildly mixed up not clear and it causes nuisance not convenience. > (Heck, I don't even remember when was the last time I needed to use > smart pointers at all.) Odd. It is hard to be more efficient than 'std::unique_ptr'. I have massive amount of those. Need for 'std::shared_ptr' is rare (since shared ownership is rare) but even less than that I need to use intrusive reference counting. > It was just an illustrative example of when virtual inheritance could > be potentially useful. Like I said it felt at least imaginable bonus on case when intrusive reference-counting is somehow needed for resource management. |
Juha Nieminen <nospam@thanks.invalid>: Jul 01 12:57PM > large enough to hold both the pointed-to data and its internal info. If > it does, that would be just as efficient as an intrusive pointer, > without being that 'intrusive'. If that's the case, then it's much better than using std::shared_ptr with 'new' directly. --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
Juha Nieminen <nospam@thanks.invalid>: Jul 01 01:00PM > massive amount of those. Need for 'std::shared_ptr' is rare (since shared > ownership is rare) but even less than that I need to use intrusive reference > counting. The reason I don't usually use smart pointers at all is because I usually don't allocate memory explicitly. I tend to either use the standard data containers, or objects by value (if it's feasible and efficient). Of course it depends on the application how much explicit dynamic allocation of objects is needed. --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
"Öö Tiib" <ootiib@hot.ee>: Jul 01 09:07AM -0700 On Wednesday, 1 July 2015 13:22:50 UTC+3, Martijn van Buul wrote: > twice as much) - which caused performance issues. > The problem at hand revolved around a variant[1] of boost::any. boost::any > has performance issues, because it relies on dynamic allocation. I have used 'boost::variant'. It is bit simpler to use, works faster and does more things compile-time than 'boost::any'. It anyway feels not relevant. > Before you dismiss this as premature optimalisation: It wasn't. It reduced > runtime *of the entire system* by almost 20% and reduced memory > requirements by a similar number due to a reduce in memory fragmentation. I don't dismiss it. Your design feels like hybrid of 'any' and 'variant'. I trust it does not matter for question of intrusive reference counting. > object, it needs to include at least a reference counter. It cannot combine > the held object and the counter in a single object using composition, as it > must be possible to create a shared_ptr<> from a naked pointer. There is clear need to make 'shared_ptr' from naked pointer when the naked pointer to manage comes from outside of our code (like from external library or operating system API). On these cases it is also likely difficult to add that intrusive reference count as alternative? On other cases neither feels needed. > is back (thus increasing runtime and increasing fragmentation). make_shared() > tries to work around this by allocating one block of memory for both, but then > you're back at not using the overloaded operator new. When we have custom allocator then 'std::make_shared' does not work but then it might be worth considering usage of 'std::allocate_shared' as alternative to switching to intrusive pointer. > counting object is required. > 3) It is a solution that does not depend on implementation details of > shared_ptr I do not understand how usage of 'std::allocate_shared' makes extra allocations and what internal details you have in mind. > use them unless profiling indicates that I should. However, I have enough > evidence to dispel blanket statements like "shared_ptr is more efficient". > Blanket statements are always wrong. I never make them :P. I can not say that 'shared_ptr' is *always* better than 'intrusive_ptr' because it has more features so it is more expensive (if it matters). I only wrote that virtual inheritance and diamond caused by two refcounted base classes is such a great example where 'shared_ptr' most likely wins intrusive refcounting. |
"Öö Tiib" <ootiib@hot.ee>: Jul 01 09:17AM -0700 On Wednesday, 1 July 2015 16:00:36 UTC+3, Juha Nieminen wrote: > The reason I don't usually use smart pointers at all is because I usually > don't allocate memory explicitly. I tend to either use the standard > data containers, or objects by value (if it's feasible and efficient). There seem to always be few things that are dynamically polymorphic to get rid of repetitive switch cases. Can't keep such in continuous container. > Of course it depends on the application how much explicit dynamic > allocation of objects is needed. Indeed. |
legalize+jeeves@mail.xmission.com (Richard): Jul 01 04:57PM [Please do not mail me a copy of your followup] Martijn van Buul <pino@dohd.org> spake the secret code >object, it needs to include at least a reference counter. It cannot combine >the held object and the counter in a single object using composition, as it >must be possible to create a shared_ptr<> from a naked pointer. To get the reference count and the object allocated in the same chunk of memory, you use std::make_shared. -- "The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline> The Computer Graphics Museum <http://computergraphicsmuseum.org> The Terminals Wiki <http://terminals.classiccmp.org> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com> |
Juha Nieminen <nospam@thanks.invalid>: Jul 01 08:10AM > return false; > return true; > } That doesn't actually test it correctly. It's a typical beginner mistake. Try to figure out why. --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
Paul <pepstein5@gmail.com>: Jul 01 01:58AM -0700 On Wednesday, July 1, 2015 at 9:10:36 AM UTC+1, Juha Nieminen wrote: > > } > That doesn't actually test it correctly. It's a typical beginner mistake. > Try to figure out why. In practice, the test worked. I made faulty attempts at quicksort etc. And the unsorted nature of the result was picked up, until I fixed the code. My guess is that you're referring to the signed/unsigned comparison. However, this isn't technically perfect but it isn't really a problem either. Note that the unsigned value can never be negative because we cover the case vec.empty() above. A more thorough test would also check that the vector has the size that it's supposed to have. Is that what you mean? In that case, the test would not be "incorrect", just arguably incomplete. I would also add that I did check the code against both large (1 million entries) and very small (0, 1 or 2 entries) and I didn't see any problems. If you erase if(vec.empty()) return true; then the code crashes for an empty vector. But so what? (In other words, so what if you can make the code crash by changing it? Anything can be ruined by changing it.) I'm a bit puzzled by your comment. Please could others give feedback about whether they agree that the test is flawed? If it is flawed in an interesting way, then I agree that it would be a good learning experience to fix it. Thank You, Paul |
Ralf Goertz <me@myprovider.invalid>: Jul 01 12:15PM +0200 Am Wed, 1 Jul 2015 01:58:01 -0700 (PDT) > Please could others give feedback about whether they agree that the > test is flawed? If it is flawed in an interesting way, then I agree > that it would be a good learning experience to fix it. What about equal elements in vec? |
Ralf Goertz <me@myprovider.invalid>: Jul 01 12:23PM +0200 Am Wed, 1 Jul 2015 12:15:25 +0200 > > test is flawed? If it is flawed in an interesting way, then I agree > > that it would be a good learning experience to fix it. > What about equal elements in vec? Sorry, I misread the code for something like bool ret=true for (…) ret&=(vec[i] < vec[i + 1] ) return ret; So I also don't see the problem. |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 01 12:45PM +0200 On 01-Jul-15 10:58 AM, Paul wrote: > Please could others give feedback about whether they agree that the test is > flawed? If it is flawed in an interesting way, then I agree that it would > be a good learning experience to fix it. I see no problem with other than that it may produce spurious warnings about signed/unsigned comparison (which however is safe). Cheers & hth., - Alf -- Using Thunderbird as Usenet client, Eternal September as NNTP server. |
Paul <pauldanielepstein@gmail.com>: Jul 01 05:03AM -0700 On Wednesday, July 1, 2015 at 11:45:18 AM UTC+1, Alf P. Steinbach wrote: > > be a good learning experience to fix it. > I see no problem with other than that it may produce spurious warnings > about signed/unsigned comparison (which however is safe). Great that others agree with me. Yes, the code does produce spurious warnings on my compiler with its current setting. Ignoring the possibility of an unsigned value becoming negative (and therefore overflowing) is indeed a common "beginner's error" so this seems a good guess about what Juha meant. However, Juha seems to have overlooked the if(vec.empty()) code which protects against that error. Paul |
Paul <pauldanielepstein@gmail.com>: Jul 01 05:08AM -0700 On Wednesday, July 1, 2015 at 1:00:46 PM UTC+1, Stefan Ram wrote: > >Try to figure out why. > He uses »int i«, but »vec.max_size()« could > be larger than numeric_limits< int >::max(). Yes, but this is too small a quibble for the assertion that the code "doesn't test it correctly." The code works for vector sizes that are less than both vec.max_size() and maxint and that should be good enough. I doubt whether Juha meant this. Paul Paul |
Juha Nieminen <nospam@thanks.invalid>: Jul 01 01:09PM > I'm a bit puzzled by your comment. The problem with the function is that it tests that the parameter is sorted, but it doesn't verify that your sorting algorithm actually works correctly. To understand why, consider that this "sorting function" passes with flying colors your test: std::vector<int> FalseSort1(std::vector<int> v) { return std::vector<int>(); } Likewise this does as well: std::vector<int> FalseSort2(std::vector<int> v) { return std::vector<int>(v.size(), 0); } This is not just nitpicking. You can't test the validity of a custom sorting function by simply checking that the result is sorted. You also have to test that the result actually has all the same values as the input had. Else you won't be catching bugs where elements are accidentally dropped off, duplicated or corrupted in some other way. (It's an interesting question *how* you would test that. Of course the simplest way of doing it is to sort the original with std::sort(), which is known to be reliable, and then compare the two vectors. If there were no reliable readymade sorting function available, then the checking becomes more interesting.) --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
ram@zedat.fu-berlin.de (Stefan Ram): Jul 01 12:00PM >>for(int i = 0; i < vec.size() - 1; ++i) >That doesn't actually test it correctly. It's a typical beginner mistake. >Try to figure out why. He uses »int i«, but »vec.max_size()« could be larger than numeric_limits< int >::max(). |
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 30 08:53PM -0400 On 6/30/2015 4:52 PM, Stefan Ram wrote: > int main() { if( ::std::puts( "hello, world" )){} } > , and I just wanted to show that you can program without the > semicolon »;«! You can't guarantee that <cstdio> header does not contain a semicolon. V -- I do not respond to top-posted replies, please don't ask |
Ian Collins <ian-news@hotmail.com>: Jul 01 01:55PM +1200 Stefan Ram wrote: > int main() { if( ::std::puts( "hello, world" )){} } > , and I just wanted to show that you can program without the > semicolon »;«! You can also program without the superfluous colons! -- Ian Collins |
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 30 08:51PM -0400 On 6/30/2015 6:16 PM, Stefan Ram wrote: >> in which 'a' does *not* have to be a single expression (see p13). > That quotation from above did not explictly refer to > direct-initializations only AFAIK. No, but the definition of 'direct-initialization' specifies those two forms. The 'If the entry being...' portion provides a special case for non-class objects. > (it is possible that it is neither a copy-initialization nor > a direct-initialization, but just »an initialization«). The > quotation than could refer to this. There is no such thing as "just an initialization". They are all either direct- or copy- or default- or zero- or value- or list-. There is no other type. V -- I do not respond to top-posted replies, please don't ask |
Fraser Ross <fraser.ross8ATbtinternet.com@com>: Jun 30 02:28PM +0100 On 30/06/2015 06:34, JiiPee wrote: > So, if me also have done that (and its rare I press wrong buttons in > programs) - and others as well - that is a good indication that the > design makes people easy to do it the wrong way. I don't think the default set of buttons has those ones. On the Message menu there is New Message at the top whether your on email or newsgroups so you easily start the wrong type of message. Fraser. |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment