On 21/01/2023 19:09, R.Wieser wrote:
> "Mike Terry" <
news.dead.p...@darjeeling.plus.com> wrote in message
> news:tPqdnZTbnINss1H-...@brightview.co.uk...
>
>> the question deserves a literal answer.
>
> Thats what I thought too.
>
>> The answer is that the documentation for using the function in question
>> needs to clearly specify whether or not the caller is responsible for
>> freeing particular resources returned by the function.
>
> My post was more in the direction that /either of/ those string types could
> be returned, and I would like to create a "safe release" routine for such a
> pointer.
A noble aim, but... the C++ and C language raw pointers are basically just "pointers to type xxx"
They don't encapsulate how to free referenced resource(s) - pointers to an object on the stack, or
in static program storage, or on the C/C++ heap or even in the OS process heap will all typically
look similar, i.e. just 32- or 64-bit (or whatever) address space pointer values. You could analyse
the pointer value and try to work out what region of memory it belongs to, but that will be
non-portable and too much to reasonably ask, I'd say.
C++ functions could return some kind of embellished pointer - a class object including the pointer
and also the capability within the class of freeing the referenced resources in various ways
depending on how the resource was created. The embellishment would increase the memory required for
a 'pointer', so this might not be a good idea e.g. if your app might have large arrays of such
pointers. Basically, if there were a /simple/ answer to your original question, there would be no
interesting debate, but there's not - so you need to carefully balance costs/benefits. Simple is
good, unless simple doesn't work! :)
>> Of course, if you're writing the called function, and want to return some
>> literal string, you would need to strdup() that literal string yourself,
>> so that it can be correctly freed by the caller.
>
> Thats good for a simple situation. I was also thinking of a string pointer
> which could be initialized by the user but changed by a routine.
There are two aspects here, and it's good to keep them separate.
Looking at the std::string class, that addresses the "initialized by the user but changed by a
routine" bit of the problem, which I'll suggest is 99% of the benefit you're after. [Pass strings
as std::string& ]
The remaining "I really want to return pointers to memory allocated (and so to be later freed) in
several different ways decided at run-time ALL FROM THE SAME FUNCTION" is a separate problem. It
could be addresed with the approach of embellished pointers. The standard library supports custom
allocators which can serve as template arguments for containers like std::string, so you could have
a std::string with an embellished pointer - but, so much added complexity for what??
If you're more interested in C APIs, using raw pointers etc., then the whole topic of
responsibilities for managing memory between callers and called functions IN GENERAL is quite
subtle. DCE's Remote Procedure Call (RPC) framework has to solve this issue because the calling and
called routines typically are in different address spaces with no shared memory, and it's far from
trivial! The problem is that C/C++ language in itself does not sufficiently describe pointer use to
make this possible. E.g. a pointer could be a REF pointer to a single struct, or to an array, and
structs can chain to other structs, possibly involving loops of pointers, or at least having
multiple pointers to a single struct. Also pointers need to be understood as IN/OUT/INOUT in terms
of which way data is being passed to/from a function, which affects the rules for managing the
memory. If you're interested in the GENERAL solution for this kind of problem the DCE RPC
documentation (or Microsofts DCOM which uses RPC) relating to memory management would at least give
you a good idea of the issues.
But if you just want to provide one C-style API for one function with a modifiable IN/OUT parameter,
just do something like:
int AmendString (/*INOUT*/ char** ppString);
and clearly document callers responsibity, including how the string memory must initially be
allocated by the caller, and how it must eventually be freed upon return.
Mike.