in reply to Re: C++ strings, references and XS (char*)
in thread C++ strings, references and XS

I thought about doing that, the problem is that I don't know how would that affect memory handling. I mean, If I'd had a function like this in C++:

string bleh(void);

I could easily have a C wrapper that would do:

const char* blehC(void) { return bleh(void).c_str(); }

But... this has a big problem: you are returning a pointer to a local variable (the returned string inside blehC is local to blehC).

So, what I would need is to tell XS/perl/whatever to give me a piece of memory that it considers a scalar where I can write to (wether it is a scalar being returned or a reference to a scalar which I receive). I guess that I don't have an alternative to write something in the CODE: section, but I really wouldn't know how to do that nor how the C/C++ function should look like. I mean, in C I don't have references, so I would be taking a char*, but... how do I know how much space do I have to write? When I write to a std::string I'm indirectly allocating memory and returning to something a user gave me. So, at C level, how does XS/perl/whatever knows how to free the memory I return? assuming that I do something like this:

char* respondC(const char* input, const char* username) { char* ret = NULL; if (respond(input, username, cpp_ret)) { string cpp_ret; ret = new char[cpp_ret.length()+1]; strncpy(ret, cpp_ret.c_str(), cpp_ret.length()); } return ret; }
(ignoring possible fencepost errors)

So, that is what is haunting me... Maybe there's a way to not even write at CODE: but just write a C function that takes a scalar reference (SV* or something like that) where I can copy (as a string) the result of the C++ function. Anyway, that would be ideal, not sure if possible.

Replies are listed 'Best First'.
Re^3: C++ strings, references and XS (char*)
by tye (Sage) on Dec 20, 2005 at 16:31 UTC
    the problem is that I don't know how would that affect memory handling

    That is why I said (emphasis added):

    or grab output.c_str() for the XS to copy into the returned PV for the other

    You write a C++ function that has a lexical std::string that it passes to the method for the method to fill in. Then you copy the value from output.c_str() to a Perl PV (part of an SV). The handling of a RETVAL of type "char*" will do this copying automatically.

    I suppose it becomes a problem if you can't get the XS code to be treated as C++ such that the XS routine is where you declare the output std::string. Though I'm pretty sure this is possible, I also realize that it at least used to be somewhat difficult, requiring some undocumented fiddling.

    If I wanted to avoid that complication, then I'd have the middle-man C++ function take two input "char*"s (still) and one output SV* (see your typemap file for the simple incantation required to copy a '\0'-terminated "char*" into the PV of an SV).

    - tye        

      I'm sorry for misreading your answer (not enough caffeine).

      I tried what I understood from you response and... it works! Thanks a lot for helping me. For any other person out there the xs that made it work was (note that the substantial changes are in the respond function, the rest was just because there was no more need to use the derived class):

      #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #ifdef __cplusplus } #endif #include <string> #include <libaiml/core.h> using std::string; using aiml::cCore; using aiml::AIMLError; MODULE = AI::AIML PACKAGE = AI::AIML cCore * cCore::new() void cCore::DESTROY() bool cCore::initialize(const char* file) void cCore::deinitialize() long cCore::get_error() const char* cCore::get_error_str(AIMLError error_num); const char* cCore::respond(const char* input, const char* username) CODE: string out; if (!THIS->respond(input, username, out)) XSRETURN_UNDEF; else RETVAL = out.c_str(); OUTPUT: RETVAL

      I obviously also changed the typemap accordingly (cAiml -> cCore).

      Don't know if you know what AIML is (you can google that), but if you do, you may understand my happiness when I read this:

      PERL_DL_NONLAZY=1 /usr/bin/perl5.8.6 "-MExtUtils::Command::MM" "-e" "t +est_harness(0, 'blib/lib', 'blib/arch')" t/*.t t/AI-AIML....ok 3/4# Returned: Hello there. + t/AI-AIML....ok + All tests successful. Files=1, Tests=4, 8 wallclock secs ( 7.48 cusr + 0.16 csys = 7.64 C +PU)
      (notice the "Returned", as an aswer to "hi") =] Thanks a lot.