On 02/06/10 09:23, Bruce Momjian wrote: > Tom Lane wrote: >> Craig Ringer <craig@xxxxxxxxxxxxxxxxxxxxx> writes: >>> On 01/06/10 11:05, Tom Lane wrote: >>>> I'd be interested to see a section like this written by someone who'd >>>> actually done a nontrivial C++ extension and lived to tell the tale. >> >>> I can't speak up there - my own C++/Pg backend stuff has been fairly >>> trivial, and has been where I can maintain a fairly clean separation of >>> the C++-exposed and the Pg-backend-exposed parts. I was able to keep >>> things separate enough that my C++ compilation units didn't include the >>> Pg backend headers; they just exposed a pure C public interface. The Pg >>> backend-using compilation units were written in C, and talked to the C++ >>> part over its exposed pure C interfaces. >> >> Yeah, if you can design your code so that C++ never has to call back >> into the core backend, that eliminates a large chunk of the pain. >> Should we be documenting design ideas like this one? > > I have incorporated the new ideas into the C++ documentation section, > and removed the comment block in the attached patch. If you're going to include that much, I'd still really want to warn people about exception/error handling too. It's important. I made brief mention of it before, but perhaps some more detail would help if people really want to do this. ( BTW, all in all, I agree with Tom Lane - the best answer is "don't". Sometimes you need to access functionality from C++ libraries, but unless that's your reason I wouldn't ever consider doing it. ) Here's a rough outline of the rules I follow when mixing C/C++ code, plus some info on the longjmp error handling related complexities added by Pg: Letting an exception thrown from C++ code cross into C code will be EXTREMELY ugly. The C++-to-C boundaries *must* have unconditional catch blocks to convert thrown exceptions into appropriate error codes, even if the C++ code in question never knowingly throws an exception. C++ may throw std::bad_alloc on failure of operator new(), among other things, so the user must _always_ have an unconditional catch. Letting an exception propagate out to the C-based Pg backend is rather likely to result in a backend crash. If the C++ libraries you are using will put up with it, compile your C++ code with -fno-exceptions to make your life much, much easier, as you can avoid worrying about this entirely. OTOH, you must then check for NULL return from operator new(). If you can't do that: My usual rule is that any "extern C" function *must* have an unconditional catch. I also require that any function that may be passed as a function pointer to C code must be "extern C" and thus must obey the previous rule, so that covers function pointers and dlopen()ed access to functions. Similarly, calling Pg code that may use Pg's error handling from within C++ is unsafe. It should be OK if you know for absolute certain that the C++ call tree in question only has plain-old-data (POD) structs and simple variables on the stack, but even then it requires caution. C++ code that uses Pg calls can't do anything it couldn't do if you were using 'goto' and labels in each involved function, but additionally has to worry about returning and passing non-POD objects between functions in a call chain by value, as a longjmp may result in dtors not being properly called. The best way to get around this issue is not to call into the Pg backend from C++ code at all, instead encapsulating your C++ functionality into cleanly separated modules with pure C interfaces. If you don't #include any Pg backend headers into any compilation units compiled with the C++ compiler, that should do the trick. If you must mix Pg calls and C++, restrict your C++ objects to the heap (ie use pointers to them, managed with new and delete) and limit your stack to POD variables (simple structs and built-in types). Note that this means you can't use std::auto_ptr, std::tr1:shared_ptr, RAII lock management, etc in C++ code that may call into the Pg backend. -- Craig Ringer Tech-related writing: http://soapyfrogs.blogspot.com/ -- Sent via pgsql-general mailing list (pgsql-general@xxxxxxxxxxxxxx) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-general