Performance of passing unique_ptr vs. raw pointer to functions

185 views Asked by At

I am working on a program which passes message objects through a chain of functions which are dealing with the messages like doing calculations, storing, queueing, formating, ...

Till now the objects are passed as raw pointer. But using raw pointer causes the risk of memory leaks or missuse of message which are already passed. So, we are considering to switch to unique pointers which would be much more safe.

However, since performence is very important, we don't want to get a performance degradation when switching to unique pointers. But most information I found concerning performance impact of unique pointers was about creation and deleting, but not about passing them through a chain of functions.

I run some tests which small examples which are simply passing long integers through functions.

Raw pointer:

#include <iostream>
#include <memory>

unsigned long gNbrFuncCalls;

void inc2(unsigned long *inInt);
void inc3(unsigned long *inInt);

void inc(unsigned long *inInt)
{
   ++*inInt;
   if (*inInt < gNbrFuncCalls)
   {
      inc2(std::move(inInt));
   }
   else
   {
      delete inInt;
   }
}

void inc2(unsigned long *inInt)
{
   ++*inInt;
   if (*inInt < gNbrFuncCalls)
   {
      inc3(std::move(inInt));
   }
   else
   {
      delete inInt;
   }
}

void inc3(unsigned long *inInt)
{
   ++*inInt;
   if (*inInt < gNbrFuncCalls)
   {
      inc(std::move(inInt));
   }
   else
   {
      delete inInt;
   }
}


int main( int argc, const char* argv[] )
{
   if (argc != 3)
   {
      printf ("\nusage: %s nbr_of_iterations nbr_of_function_calls\n\n", argv[0]);
      return 1;
   }

   char* p;
   unsigned long nbrIt = strtoul(argv[1], &p, 10);

   if (*p != '\0' || errno != 0) {
      printf ("\nusage: %s nbr_of_iterations nbr_of_function_calls\n\n", argv[0]);
      return 1; // In main(), returning non-zero means failure
   }

   gNbrFuncCalls = strtoul(argv[2], &p, 10);

   if (*p != '\0' || errno != 0) {
      printf ("\nusage: %s nbr_of_iterations nbr_of_function_calls\n\n", argv[0]);
      return 1; // In main(), returning non-zero means failure
   }

   for (int i = 0; i < nbrIt; ++i)
   {
      inc(std::move(new unsigned long(0)));

   }

   printf("\n%lu iterations with %lu function calls done.\n\n", nbrIt, gNbrFuncCalls);
   return 0;
}

Unique pointer:

#include <iostream>
#include <memory>

unsigned long gNbrFuncCalls;

void inc2(std::unique_ptr<unsigned long> inInt);
void inc3(std::unique_ptr<unsigned long> inInt);

void inc(std::unique_ptr<unsigned long> inInt)
{
   ++*inInt;
   if (*inInt < gNbrFuncCalls)
   {
      inc2(std::move(inInt));
   }
}

void inc2(std::unique_ptr<unsigned long> inInt)
{
   ++*inInt;
   if (*inInt < gNbrFuncCalls)
   {
      inc3(std::move(inInt));
   }
}

void inc3(std::unique_ptr<unsigned long> inInt)
{
   ++*inInt;
   if (*inInt < gNbrFuncCalls)
   {
      inc(std::move(inInt));
   }
}

int main( int argc, const char* argv[] )
{
   if (argc != 3)
   {
      printf ("\nusage: %s nbr_of_iterations nbr_of_function_calls\n\n", argv[0]);
      return 1;
   }

   char* p;
   unsigned long nbrIt = strtoul(argv[1], &p, 10);

   if (*p != '\0' || errno != 0) {
      printf ("\nusage: %s nbr_of_iterations nbr_of_function_calls\n\n", argv[0]);
      return 1; // In main(), returning non-zero means failure
   }

   gNbrFuncCalls = strtoul(argv[2], &p, 10);

   if (*p != '\0' || errno != 0) {
      printf ("\nusage: %s nbr_of_iterations nbr_of_function_calls\n\n", argv[0]);
      return 1; // In main(), returning non-zero means failure
   }

   for (int i = 0; i < nbrIt; ++i)
   {
      auto upInt = std::make_unique<unsigned long>(0);

      inc(std::move(upInt));

   }

   printf("\%lu iterations with %lu function calls done.\n\n", nbrIt, gNbrFuncCalls);
   return 0;
}

No matter if I compile both with or without optimization, when running them using time to meassure the runtime, the test using the unique pointers runs about 10 till 12 times longer, e.g.:

> time ./testUniquePtr 1000 750000
1000 iterations with 750000 function calls done.


real    0m2.106s
user    0m2.102s
sys     0m0.004s

> time ./testRawPtr 1000 750000

1000 iterations with 750000 function calls done.


real    0m0.187s
user    0m0.186s
sys     0m0.001s

Sure, these tests are very simple since I am just increasing the number. However, does really it mean that the unique pointer slower, or do I something wrong?

0

There are 0 answers