toStringz note about keeping references

Andrej Mitrovic andrej.mitrovich at gmail.com
Sun Oct 14 16:36:27 PDT 2012


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".

I'd really like to know for sure if the GC implementation actually
collects immutable data or not. 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.
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? 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
    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.

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.

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.


More information about the Digitalmars-d-learn mailing list