c++performancec++11stl

Is simple but frequent usage of std::stringstream a premature pessimization?


I have a simple scenario. I need to join two C-strings together into a std::string. I have decided to do this in one of two ways:

Solution 1

void ProcessEvent(char const* pName) {
   std::string fullName;
   fullName.reserve(50); // Ensure minimal reallocations for small event names (50 is an arbitrary limit).
   fullName += "com.domain.events.";
   fullName += pName;

   // Use fullName as needed
}

Solution 2

void ProcessEvent(char const* pName) {
   std::ostringstream ss;
   ss << "com.domain.events." << pName;

   std::string fullName{ss.str()};
   // Use fullName as needed
}

I like solution 2 better because the code is more natural. Solution 1 seems like a response to a measurable bottleneck from performance testing. However, Solution 1 exists for 2 reasons:

  1. It's a light optimization to reduce allocations. Event management in this application is used quite frequently so there might be benefits (but no measurements have been taken).
  2. I've heard criticism regarding STL streams WRT performance. Some have recommended to only use stringstream when doing heavy string building, especially those involving number conversions and/or usage of manipulators.

Is it a premature pessimization to prefer solution 2 for its simplicity? Or is it a premature optimization to choose solution 1? I'm wondering if I'm too overly concerned about STL streams.


Solution

  • Let's measure it

    A quick test with the following functions:

    void func1(const char* text) {
        std::string s;
        s.reserve(50);
        s += "com.domain.event.";
        s += text;
    }
    
    void func2(const char* text) {
        std::ostringstream oss;
        oss << "com.domain.event." << text;
        std::string s = oss.str();
    }
    

    Running each 100 000 times in a loop gives the following results on average on my computer (using gcc-4.9.1):

    func1 : 37 milliseconds

    func2 : 87 milliseconds

    That is, func1 is more than twice as fast.

    That being said, I would recommend using the clearest most readable syntax until you really need the performance. Implement a testable program first, then optimize if its too slow.

    Edit:

    As suggested by @Ken P:

    void func3(const char* text) {
        std::string s = "com.domain.event" + std::string{text};
    }
    

    func3 : 27 milliseconds

    The simplest solution is often the fastest.