toStringz note about keeping references
Ali Çehreli
acehreli at yahoo.com
Sun Oct 14 16:54:15 PDT 2012
On 10/14/2012 04:36 PM, Andrej Mitrovic wrote:
> On 10/15/12, Jonathan M Davis<jmdavisProg at gmx.com> wrote:
>> I'd have to see exactly what TDPL says to comment on that accurately
>
> Maybe I've misread it. On Page 288 it says:
>
> "An immutable value is cast in stone: as soon as it's been
> initialized, you may as well
> consider it has been burned forever into the memory storing it. It
> will never change
> throughout the execution of the program."
>
> Perhaps what was missing is: "as long as there is a reference to that
data".
Andrei must have written that only D in mind, without any C interaction.
When we consider only D, then the statement is correct: If there is no
more references, how can the application tell that the data is gone or not?
> I'd really like to know for sure if the GC implementation actually
> collects immutable data or not.
It does. Should be easy to test with an infinite loop that generates
immutable data.
> I've always used toStringz in direct
> calls to C without caring about keeping a reference to the source
> string in D code. I'm sure others have used it like this as well.
It depends on whether the C-side keeps a copy of that pointer.
> Maybe the only reason my apps which use C don't crash is because a GC
> cycle doesn't often run, and when it does run it doesn't collect the
> source string data (either on purpose or because of buggy behavior, or
> because the GC is imprecise).
>
> Anyway this stuff is important for OOP wrappers of C/C++ libraries. If
> the string reference must kept on the D side then this makes writing
> wrappers harder. For example, let's say you've had this type of
> wrapper:
>
> extern(C) void* get_Foo_obj();
> extern(C) void* c_Foo_test(void* c_obj, const(char)* input);
>
> class Foo
> {
> this() { c_Foo_obj = get_Foo_obj(); } // init c object by calling
> a C function
>
> void test(string input)
> {
> c_Foo_test(c_Foo_obj, toStringz(input));
> }
>
> void* c_Foo_obj; // reference to C object
> }
>
> Should we always store a reference to 'input' to avoid GC collection?
If the C function copies the pointer, yes.
> E.g.:
>
> class Foo
> {
> this() { c_Foo_obj = get_Foo_obj(); } // init c object by calling
> a C function
>
> void test(string input)
> {
> input_ref = input
> c_Foo_test(c_Foo_obj, toStringz(input));
> }
>
> string input_ref; // keep it alive, C might use it after test()
returns
That's exactly what I do in a C++ library that wraps C types.
> void* c_Foo_obj; // reference to C object
> }
>
> And what about multiple calls? What if on each call to c_Foo_test()
> the C library stores each 'input' pointer internally? That would mean
> we have to keep an array of these pointers on the D side.
Again, that's exactly what I do in C++. :) There is a global container
that keeps the objects alive.
> It's not know what the C library does without inspecting the source of
> the C library. So it becomes very difficult to write wrappers which
> are GC-safe.
Most functions document what they do with the input parameters. If not,
it is usually obvious.
> There are wrappers out there that seem to expect the source won't be
> collected. For example GtkD also uses toStringz in calls to C without
> ever storing a reference to the input string.
Must be verified case-by-case.
Ali
More information about the Digitalmars-d-learn
mailing list