Boost logo

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