0

In a member function, I want to return a newly created vector of strings. Which version is the most efficient from a memory allocation & constructor calling point of view? theString(i) returns a const std::string &

std::vector<std::string> result(depth());
for(int i=0;i<depth;i++) {
    result[i] = theString(i);
}

or

std::vector<std::string> result;
result.reserve(depth());
for(int i=0;i<depth;i++) {
    result.emplace_back(theString(i));
}

To me it seems that:

  • Solution 1 constructs every empty string first, then copy-assigns them => not perfect
  • Solution 2 is better since it will copy-construct every string, while the vector data is allocated once by reserve

(or is there an even more efficient solution?)

12
  • which code snippet is easier to maintain, or to ignore when hunting for a bug, so on Commented May 11, 2014 at 17:30
  • 2
    I would imagine that your compiler would optimize both to the same code, check the assembly output for both and see if there are any differences. As Alf mentioned, readability is far more important than these micro optimizations though. So go with whatever is easiest to read and maintain. Commented May 11, 2014 at 17:30
  • 1
    Well, there is no much difference in readability, and it's definitely in a speed critical section. Commented May 11, 2014 at 17:32
  • 2
    The Rules of Optimization Club Apply the second rule. Commented May 11, 2014 at 17:38
  • @shuttle87: actually, that's pretty unlikely. But whether it makes a difference in speed is another question. Commented May 11, 2014 at 17:40

1 Answer 1

2

It's impossible to give a generic answer: depending on your compiler, the Standard Library implementation than you are using, the target CPU and the surrounding source code, the emitted code may vary. Furthermore, whether one solution or the other is faster may also be affected by cache effects or thread-switching effects caused by different scheduling.

So, unfortunately, there is no generic answer: measure with your setup.

That being said, let me offer two other candidates; candidate 3:

// The simplest code is always easier to read:
std::vector<std::string> result;
for (size_t i = 0; i < depth; ++i) { result.emplace_back(theString(i)); }

I would be surprised if it were much worse than your candidate 2. It relies on vector's amortized constant emplace_back and the fact that moving strings is cheap (compared to copying).

And candidate 4:

// If no copy is necessary, then no copy is cheaper:
std::vector<std::string_view> result; // or another "StringRef" alternative
for (size_t i = 0; i < depth; ++i) { result.emplace_back(theString(i)); }

The latter relying on string_view: a non-owning reference to a string which is a very simply thing to implement (basically, a pair size_t and char const*) but is only viable if the referenced string is guaranteed to outlive the last use of the string_view.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.