2

I'm thinking about proposing the following as an alternative to sprintf/snprintf in our project.

The motivation is to remove the need to think about buffer sizes and keep as much of the convenience of the original as possible.

std::string strprintf(const char *format, ...)
{
    std::string s;
    s.resize(128); // best guess
    char *buff = const_cast<char *>(s.data());

    va_list arglist;
    va_start(arglist, format);
    auto len = vsnprintf(buff, 128, format, arglist);
    va_end(arglist);

    if (len > 127)
    {
        va_start(arglist, format);
        s.resize(len + 1); // leave room for null terminator
        buff = const_cast<char *>(s.data());
        len = vsnprintf(buff, len+1, format, arglist);
        va_end(arglist);
    }
    s.resize(len);
    return s; // move semantics FTW
}

Does this code have any inherent problems?

usage example:

auto s = strprintf("Hello %d world", 777);
CplusPuzzle
  • 298
  • 2
  • 9
  • *"convenience of the original"* - That's highly debatable. – StoryTeller - Unslander Monica Aug 10 '17 at 08:19
  • It seems technically correct, but not very performant if the buffer exceeds your 128 size cap. It calls vsnprintf again, making the function take twice as long. You have to weigh between convenience and performance here. Additionally, the string you return will be copied again - which further impacts performance. – Freakyy Aug 10 '17 at 08:22
  • The return value has move semantics, so there shouldn't be another copy. – CplusPuzzle Aug 10 '17 at 08:53
  • I think the compiler only optimizes `vsnprintf` with a size of 0. Also, `&s[0]` to avoid the `const_cast`. – o11c Aug 14 '17 at 05:25
  • casting away const on `s.data()` and writing to it is undefined behaviour. You should use `&s[0]` – M.M Aug 14 '17 at 05:33
  • A major problem with this is that it breaks for incorrect format specifier still – M.M Aug 14 '17 at 05:34
  • So, all the type safety of sprintf combined with all the extensibility of sprintf? Anyway, [codereview.se] may be a better fit – n. 1.8e9-where's-my-share m. Aug 14 '17 at 05:45

1 Answers1

0

Turns out that there's already much discussion on this here:

std::string formatting like sprintf

Subjectively, my version still looks more concise than most stuff there, but it's functionally identical to some of the proposed solution on that thread.

CplusPuzzle
  • 298
  • 2
  • 9