Re: Generic C++ templates/library for FreeBSD base

From: Dimitry Andric <dim_at_FreeBSD.org>
Date: Fri, 14 Mar 2025 14:59:44 UTC
On 14 Mar 2025, at 15:45, John Baldwin <jhb@FreeBSD.org> wrote:
> 
> On 3/14/25 09:50, Dimitry Andric wrote:
>> On 14 Mar 2025, at 14:36, John Baldwin <jhb@FreeBSD.org> wrozte:
>>> 
>>> On 3/14/25 00:19, Gleb Popov wrote:
>>>> On Thu, Mar 13, 2025 at 11:53 PM John Baldwin <jhb@freebsd.org> wrote:
>>>>> 
>>>>> One is a stringf() function that accepts printf() style format string and
>>>>> arguments and returns a std::string.  I know C++23 adds <format>, but we
>>>>> can't assume that yet, and this function is probably more useful when
>>>>> adapting existing C code.  Compared to some other solutions, I chose to
>>>>> wrap asprintf() and do an extra copy at the end into a std::string rather
>>>>> than calling vsnprintf() twice.  It seems less ugly than the vsnprintf()
>>>>> solutions also:
>>>>> 
>>>>> https://github.com/freebsd/freebsd-src/commit/01bd3d89ddf9ccbf884e52fe7289e8a9278e2d63
>>>> I wonder why std::string always copies the data passed into the constructor.
>>>> It is possible to avoid extra alloc by returning a std::string_view,
>>>> but this would force the caller into freeing the memory manually.
>>>> Maybe derive from it and extend the destructor, but this just brings
>>>> me to the initial question.
>>> 
>>> What you would want is something where you could do std::move() of the pointer
>>> returned by asprintf(), into the std::string object, but that assumes that
>>> new/delete are always using malloc/free (which is probably true in practice).
>> The ideal solution would be to define an "inserter" that can be called
>> from the guts of __vfprintf() (or wherever the "real" implementation of
>> printf lives), whenever it wants to emit a character into the output
>> buffer. And there you would simply do string::push_back(), which is
>> amortized constant time.
> 
> That you could do with funopen() where the write method called string::push_back().
> This is actually how asprintf (and open_memstream) works internally.  Maybe I will
> just fix my implementation to do that.

There is one fly in the ointment, however. The method of calling
asprintf() and then putting the result into fresh std::string moves the
possibility of exceptions to that point. But if you effectively call
string::push_back() from within a C function, you have to put a
try/catch block around it, and report an error in case you catch some
exception.

-Dimitry