Search code examples
c++c++11shared-ptr

Is an empty aliasing shared_ptr a good alternative to a no-op deleting shared_ptr?


Sometimes I need shared_ptr instances that have a no-op deleter, because an API expects a shared_ptr instance that it wants to store for a limited time but I am given a raw pointer that I am not allowed to own for a time larger than what I am running for.

For this case, I have been using a no-op deleter, such as [](const void *){}, but today I found that there's another alternative to that, using (or abusing?) the aliasing constructor of shared_ptr:

void f(ExpectedClass *ec) {
   std::shared_ptr<ExpectedClass> p(std::shared_ptr<void>(), ec);
   assert(p.use_count() == 0 && p.get() != nullptr);
   apiCall(p);
}

My question is, what is the better way to do this and why? Are the performance expectations the same? With a no-op deleter I expect to pay some cost for the storage of the deleter and reference count, which doesn't appear to be the case when using the aliasing constructor with the empty shared_ptr.


Solution

  • Quick bench with

    #include <memory>
    
    static void aliasConstructor(benchmark::State& state) {
      for (auto _ : state) {
        int j = 0;
        std::shared_ptr<int> ptr(std::shared_ptr<void>(), &j);
        benchmark::DoNotOptimize(ptr);
      }
    }
    
    BENCHMARK(aliasConstructor);
    
    static void NoOpDestructor(benchmark::State& state) {
      for (auto _ : state) {
        int j = 0;
        std::shared_ptr<int> ptr(&j, [](int*){});
        benchmark::DoNotOptimize(ptr);
      }
    }
    
    BENCHMARK(NoOpDestructor);
    

    gives

    So alias constructor wins.