|
Boost : |
From: Peter Dimov (pdimov_at_[hidden])
Date: 2002-01-20 06:23:32
From: "George A. Heintzelman" <georgeh_at_[hidden]>
> Peter Dimov wrote:
> > George Heintzelman wrote:
> > > I don't like adding the extra layer of indirection for *all*
shared_ptr
> > > destructor calls, in order to 'solve' this, for the destructor case
> > > only. In a policy-based smart pointer, I would support making it an
> > > available policy but not the default one.
> >
> > I'd be surprised if you could measure the added cost. Besides, the extra
> > layer of indirection has other good uses. It makes it possible to pass
> > shared_ptr<>s across exe/dll boundaries (that use different heaps.)
>
> Most times I'm sure you're right. I'm mostly concerned with the cases
> where the cases where the data members of the pointed-to object are all
> simple types, requiring no destructor calls, or ones with similarly
> simple inline destructors; then the C++ implementation can completely
> optimize away function calls except for the deallocation. I suspect
> that the layer of indirection here will make it much more unlikely for
> compilers to perform that optimization.
Measurements (VC 7, release, single-threaded):
Traditional: Allocation: 1.091, deallocation: 1.172, total: 2.263
Safe: Allocation: 1.241, deallocation: 1.402, total: 2.643
Code at the end.
This is a measurable increase (about 20% for the deallocation) but I think
that the safety and functionality it buys is worth it because:
* These are worst-case numbers; 'int' is handled by the small object
allocator, the application is single threaded, std::vector's own memory
management doesn't interfere.
* Usually a project will spend no more than 20% of the total running time in
new/delete operations, which means 3-4% total increase. (Even 20% in
new/delete is too much!)
* new/delete operations are usually avoided in performance-critical parts of
code anyway.
I think that this policy should be the default.
-- Peter Dimov Multi Media Ltd. #include <boost/shared_ptr.hpp> #include <vector> #include <cstdio> #include <ctime> static double elapsed(std::clock_t t0, std::clock_t t1) { return static_cast<double>(t1 - t0) / CLOCKS_PER_SEC; } int main() { int const n = 2 * 1024 * 1024; std::vector< boost::shared_ptr<int> > v; v.reserve(n); std::clock_t t1 = std::clock(); for(int i = 0; i < n; ++i) { v.push_back(boost::shared_ptr<int>(new int(i))); } std::clock_t t2 = std::clock(); v.resize(0); std::clock_t t3 = std::clock(); std::printf("Allocation: %.3f, deallocation: %.3f, total: %.3f\n", elapsed(t1, t2), elapsed(t2, t3), elapsed(t1, t3)); }
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk