Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How much performance difference when using string vs char array?

Tags:

c++

std

I have the following code:

char fname[255] = {0}
snprintf(fname, 255, "%s_test_no.%d.txt", baseLocation, i);

vs

std::string fname = baseLocation + "_test_no." + std::to_string(i) + ".txt";

Which one performs better? Does the second one involve temporary creation? Is there any better way to do this?

like image 316
SwiftMango Avatar asked Feb 21 '14 22:02

SwiftMango


People also ask

Is char array better than string?

Since Strings are immutable there is no way the contents of Strings can be changed because any change will produce new String, while if you char[] you can still set all his elements as blank or zero. So Storing the password in a character array clearly mitigates security risk of stealing passwords.

What is the difference between char array and string?

String refers to a sequence of characters represented as a single data type. Character Array is a sequential collection of data type char. Strings are immutable. Character Arrays are mutable.

Is char faster than string C++?

Originally Answered: Which are faster in C++ either strings or char arr[]? If we talk of speed then string is faster, but it is convenient to use char array for better modification and operation.

What is the advantage of using a char pointer as a string instead of taking an array of characters?

The one advantage that I'm seeing is that with char * it is easier to distinguish "no string provided" and "empty string provided", also it occupies less space then an array.


1 Answers

Let's run the numbers:

2022 edit:

Using Quick-Bench with GCC 10.3 and compiling with C++20 (with some minor changes for constness) demonstrates that std::string is now faster, almost 3x as much:

Char demonstrating string is now faster


Original answer (2014)

The code (I used PAPI Timers)

main.cpp

#include <iostream>
#include <string>
#include <stdio.h>
#include "papi.h"
#include <vector>
#include <cmath>
#define TRIALS 10000000

class Clock
{
  public:
    typedef long_long time;
    time start;
    Clock() : start(now()){}
    void restart(){ start = now(); }
    time usec() const{ return now() - start; }
    time now() const{ return PAPI_get_real_usec(); }
};


int main()
{
  int eventSet = PAPI_NULL;
  PAPI_library_init(PAPI_VER_CURRENT);
  if(PAPI_create_eventset(&eventSet)!=PAPI_OK) 
  {
    std::cerr << "Failed to initialize PAPI event" << std::endl;
    return 1;
  }

  Clock clock;
  std::vector<long_long> usecs;

  const char* baseLocation = "baseLocation";
  //std::string baseLocation = "baseLocation";
  char fname[255] = {};
  for (int i=0;i<TRIALS;++i)
  {
    clock.restart();
    snprintf(fname, 255, "%s_test_no.%d.txt", baseLocation, i);
    //std::string fname = baseLocation + "_test_no." + std::to_string(i) + ".txt";
    usecs.push_back(clock.usec());
  }

  long_long sum = 0;
  for(auto vecIter = usecs.begin(); vecIter != usecs.end(); ++vecIter)
  {
    sum+= *vecIter;
  }

  double average = static_cast<double>(sum)/static_cast<double>(TRIALS);
  std::cout << "Average: " << average << " microseconds" << std::endl;

  //compute variance
  double variance = 0;
  for(auto vecIter = usecs.begin(); vecIter != usecs.end(); ++vecIter)
  {
    variance += (*vecIter - average) * (*vecIter - average);
  }

  variance /= static_cast<double>(TRIALS);
  std::cout << "Variance: " << variance << " microseconds" << std::endl;
  std::cout << "Std. deviation: " << sqrt(variance) << " microseconds" << std::endl;
  double CI = 1.96 * sqrt(variance)/sqrt(static_cast<double>(TRIALS));
  std::cout << "95% CI: " << average-CI << " usecs to " << average+CI << " usecs" << std::endl;  
}

Play with the comments to get one way or the other. 10 million iterations of both methods on my machine with the compile line:

g++ main.cpp -lpapi -DUSE_PAPI -std=c++0x -O3

Using char array:

Average: 0.240861 microseconds
Variance: 0.196387microseconds
Std. deviation: 0.443156 microseconds
95% CI: 0.240586 usecs to 0.241136 usecs

Using string approach:

Average: 0.365933 microseconds
Variance: 0.323581 microseconds
Std. deviation: 0.568842 microseconds
95% CI: 0.365581 usecs to 0.366286 usecs

So at least on MY machine with MY code and MY compiler settings, I saw about a 50% slowdown when moving to strings. that character arrays incur a 34% speedup over strings using the following formula:

((time for string) - (time for char array) ) / (time for string)

Which gives the difference in time between the approaches as a percentage on time for string alone. My original percentage was correct; I used the character array approach as a reference point instead, which shows a 52% slowdown when moving to string, but I found it misleading.

I'll take any and all comments for how I did this wrong :)


2015 Edit

Compiled with GCC 4.8.4:

string

Average: 0.338876 microseconds
Variance: 0.853823 microseconds
Std. deviation: 0.924026 microseconds
95% CI: 0.338303 usecs to 0.339449 usecs

character array

Average: 0.239083 microseconds
Variance: 0.193538 microseconds
Std. deviation: 0.439929 microseconds
95% CI: 0.238811 usecs to 0.239356 usecs

So the character array approach remains significantly faster although less so. In these tests, it was about 29% faster.

like image 118
AndyG Avatar answered Sep 19 '22 12:09

AndyG