Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:


i use a C++ object package. the problem is that i am constrained in how i pass a C++ object around.

if the object is new'd in MAIN; and passed to routines (via @_); no problems
if the object is new'd in a routine; and passed to MAIN (either by return,or global var) problems (dumps core)

the odd thing is that if the object is new'd in a routine and passed to another routine (via @_) no problems.

the C++ coder claims that perl is deleting the object because perl decides it is no longer in scope.

so how do i tell PERL that this is a persistent object that it is not permitted to delete?
i've even tried declaring the object "our".

Replies are listed 'Best First'.
Re: C++ object & PERL garbage collection
by creamygoodness (Curate) on Sep 23, 2006 at 00:01 UTC
    I'm not a C++ hacker, but I think I grok the problem. Presumably you have a Perl object which is wrapping a C++ object, and the Perl object's class has a DESTROY function which deletes the C++ object. You can override that DESTROY function and stop it from cleaning up the C++ object, but you'll end up with a memory leak. Another possibility is to save a local copy of the Perl object, using the perlapi function newSVsv, so that when the last Perl-space reference drifts out of scope, you still have a reference keeping it from being destroyed.

    Caveat: this is a hard problem, and if you're not familiar with how and when DESTROY gets invoked and does its work, the above advice probably just gives you rope to hang yourself with.

    GL,

    --
    Marvin Humphrey
    Rectangular Research ― http://www.rectangular.com

      I'm wondering whether the object isn't being constructed and blessed in C++ using XS. If that's the case then I guess I could see how this might be happening. I still really want to see the code to understand what kind of brokenness is occurring here.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊


        1) we use SWIG, not XS the C++ object is a PERL HASH i can invokes methods on the object with OBJ->method() just like a PERL object! :-)

        exactly what code do you want to see?
        i sort of feel that this is a "philosophical" issue and not a "coding" mistake
        in another reply, i pointed out that OUR works.
        based on my limited understanding of OUR;
        it seems that OUR prevents PERL from deleting the C++ Object when its being passed around.
        but the OUR declaration has to be global

      i have a perl HASH which is a SWIG wrapper of a C++ object.

      if i new the object, and pass the reference around
      it sometimes works and sometimes fails.
      if NEW is in MAIN and passed "down", it works if NEW is in ROUTINE and passed "up", it fails

      and hopefully my usage of up/down is clear!
      using namespaces :
      if new'd as MAIN::object, -> works in all "lower" routines if new'd as MAIN::routineA::object -> does NOT work in MAIN

      you have a interesting point about newSVsv. it looks like i want something like that.
      i need a mechanism for PERL to never delete an object
      but i wanted to avoid using a GLOBAL variable that is OUR
      maybe that is the purpose of OUR?

        I have to say, I'm very confused by your capitalization. Perl is case-sensitive. There is no OUR, there is only our. Similarly, when you refer to MAIN, I don't know whether you're referring to the default main namespace in Perl, or something having to do with C++ or SWIG.

        I can understand your English despite the miscapitalization of words like "I". However, your Perl/C++ leaves me baffled. Can you please reformulate this message to use proper capitalization and punctuation in both the English and the code?

        --
        Marvin Humphrey
        Rectangular Research ― http://www.rectangular.com
Re: C++ object & PERL garbage collection
by diotalevi (Canon) on Sep 22, 2006 at 23:57 UTC

    A typical strategy is to package your C or C++ thing as a pointer and then make an object out of it. The key here is that perl objects are references so the thing they're pointing to is present as long as the object is. You really ought to post some of your code if you want better help.

    <c>package Bar; sub new { my ( $class, $cpp_thing ) = @_; return bless \ $cpp_thing, $class; }</code>

    ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

      i didn't post code because i don't think it's a problem where one can point at a line and say AHA!
      the SWIG module is simply :
      sub method { my @args = @_; $args[0] = tied(%{$args[0]}); my $result = C++CODE::method(@args); return $result; }
      and perl grabs the package with
      use lib (<path>) use (C++ package)

      as one would expect
      my $dsgn = new (c++_object) $dsgn->(method)

      and these lines work IF done in MAIN. if done in a routine and returned to MAIN; it dumps core.
      the object is a PERL HASH; and the address never changes when printed out. at first, i thought that meant the object is still present; but the C++ folks say otherwise.
      i'm thinking it's a namespace issue. another perl coder has declared the object as a global OUR. that seems to work only for the case :
      MAIN my C++object C++object = pckA::routine pckB::routine(C++object) PACKAGEA our C++object routine new C++object return C++object PACKAGEB routine my $C++object = @_ $C++object->method()

      and it ONLY works with OUR! so why is the OUR declaration required? is it a PERL problem with swigged objects or is the C++ code not swig/perl compatable?
        if done in a routine and returned to MAIN; it dumps core

        So the following would dump core:
        my $dsgn = create_new(); $dsgn->(method); sub create_new { my $ret = new (c++_object); return $ret; }
        I wonder what would happen if the reference count were incremented before returning:
        my $dsgn = create_new(); $dsgn->(method); sub create_new { my $ret = new (c++_object); refcnt_inc($ret); return $ret; }
        I don't think there exists a perl function/module that implements a reference count increment - in which case you'd need to do it with Inline::C/XS/SWIG. (I guess SWIG can help out there ... I know nothing about it.) Even if incrementing the reference count does work, that doesn't guarantee that it's the most appropriate thing to do.

        A simple little Inline::C script that increments the reference count:
        use warnings; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'EOC'; void refcnt_inc(SV * sv) { SvREFCNT_inc(sv); } SV * get_refcnt(SV * sv) { return newSVuv(SvREFCNT(sv)); } EOC $x = 1; print get_refcnt($x), "\n"; refcnt_inc($x); print get_refcnt($x), "\n";

        Not sure if there's anything in this post that helps .... :-)

        Cheers,
        Rob
Re: C++ object & PERL garbage collection
by syphilis (Archbishop) on Sep 23, 2006 at 00:47 UTC
    if the object is new'd in MAIN; and passed to routines (via @_); no problems
    if the object is new'd in a routine; and passed to MAIN (either by return,or global var) problems (dumps core)
    the odd thing is that if the object is new'd in a routine and passed to another routine (via @_) no problems.


    I can't quite follow that. If "the object is new'd in a routine and passed to another routine (via @_)" doesn't it first need to be passed to "MAIN" - which, you say, dumps core ? That is, how do you pass the object that was "new'd in a routine" to "another routine (via @_)" without first passing that object to "MAIN" ?

    Sorry if I'm being dumb :-)

    Anyway, seems to me that the issue is probably one that can only properly be fixed in the C++/XS code (rather than your perl code) ... but it's hard to tell from the info you've provided.

    Cheers,
    Rob
      but routines can call other routines, without first returning to MAIN, true?
      MAIN &routineA ROUTINEA &routineB ROUTINEB .....

      so a flow that works is :
      MAIN new C++object routineA(C++object) routineB(C++object)
      but a flow that does NOT work is :
      MAIN my C++object = routineA C++object->method ROUTINEA my C++object = new C++design return C++object

      yes, i agree with your last statement. ( that it is a C++ usage/style issue ) although we use SWIG, instead of XS.