On 30/07/2014 19:23, Dominique Devienne wrote:
On Wed, Jul 30, 2014 at 5:32 AM, Chris Cleeland
mailto:chris.cleeland@gmail.com> wrote: In my case, the C API is stashing the value of the pointer in a container, and passing that pointer value as an argument to the registered callback function. That's it. The C code doesn't *do* anything with the pointer because it treats it as a void*.
Then it's a badly-designed C API I'm afraid...
Not necessarily. For a single-shot callback, the simplest way to manage lifetime properly is to guarantee that the callback is called exactly once (always called, even on failure), at least if the initial operation reports success. This gives the caller a chance to clean up the object if required. For a multi-shot callback, the caller is usually expected to separately unregister the callback when it's done, or register a separate-but-related "cleanup/destroy" single-shot callback (depending on which end is more likely to trigger shutdown).
SQLite introduced a bunch of _v2 APIs (e.g. [1]) specifically to add a void(*xDestroy)(void*) argument to some of its functions taking a void* user-data argument, to address lifetime issues. That's C programming done right, which interfaces just fine with C++ and shared_ptr and co.
That cited example doesn't seem like a good design to me, but rather an afterthought. (I'm not referring to the _v2 bit, I mean that sqlite3_module contains a mixture of static and instance methods and the user-data destructor should have been one of the static methods, or instead of using user-data or static methods there should have been a defined module base type.) Probably they were hampered by backwards-compatibility issues, but I still wouldn't call it "done right". :) But this is getting off-topic and into bikeshed territory.