C++ - how format const char * using va_list and automatically manage internal buffers

73 views Asked by At

I use the standard vsnprintf() function for text formatting. It works well, but I must delete the buffer out of the function scope. I don't want to do it. I want to auto manage it. And I want to return const char*.

First, I thought that I can simply use a static buffer. But then I have a problem that I can't save multiple format() results and join them at the end, because the buffer is overwritten.

So, I wrote the function with a const char* pool. It has a limit of 1024 buffers, which is enough for my purposes, but I feel that this is not a good way to go.

Any idea how to deal with this issue?

Here is the original function:

const char * format(const char* fmt, ...)
{
    va_list vl;

    va_start(vl, fmt);
    int size = vsnprintf(0, 0, fmt, vl) + sizeof('\0');
    va_end(vl);

    char *buffer = new char [size];

    va_start(vl, fmt);
    size = vsnprintf(buffer, size, fmt, vl);
    va_end(vl);

    return buffer;
}

In some situations, I do several format() operations, so I need to save the result and merge it at the end. So, I rewrote the function to use the pool:

const char * format3(const char* fmt, ...) {
    static char **pool = new char *[1024]();
    static int sizes[1024];
    static int index = 0;
    static bool firstLoop = true;

    va_list vl;

    va_start(vl, fmt);
    int size = vsnprintf(0, 0, fmt, vl) + sizeof('\0');
    va_end(vl);

    char *buffer;

    if (firstLoop) {
        buffer = new char [size];
        pool[index] = buffer;
    } else {
        buffer = pool[index];
        int s = sizes[index];
        if (s < size) {
            delete [] buffer;
            buffer = new char [size];
            pool[index] = buffer;
        }
    }

    va_start(vl, fmt);
    size = vsnprintf(buffer, size, fmt, vl);
    va_end(vl);

    index++;
    if (index == 1024) {
        index = 0;
        firstLoop = false;
    }

    return buffer;
}
1

There are 1 answers

0
KamilCuk On

how to deal with this issue?

In C, you do not deal with the issue. In C, I would expect users to want to deallocate memory themselves, it is completely normal. In C, do not hide deallocation, let the users now what they are doing.

In C++, there are the whole object lifetime and object destructors are executed at the end of variable scope. In C++, use std::string, which exists to manage string memory and will deallocate strings automatically.

Overall, in C++, there are sstreams, in particular std::stringstream and in newer C++ there is std::format. You would typically prefer them in C++.

+ sizeof('\0');

sizeof('\0') sounds confusing, it is 4 in C and 1 in C++. Just + 1. When you are dealing with C strings, it is typical that your code is sprinkled with + 1 everywhere.