XS::Framework::Manual::SVAPI::Sv - XS::Framework Sv C++ class reference



The Perl SV* is variadic type, which actually can be Hash (HV*), Array(AV*) etc.

The Sv object may own the underlying Perl <SV*> or may not, i.e. the held SV* is NULL. That way some methods are NULL-safe, i.e. they can be invoked when SV* is NULL; the other methods are NULL-unsafe, and inoking them leads to undefined behaviour, most likely the program will crash.

Sv class tried to follow DWIM-principle whenever it is possible and zero- or minimal costs. For example:

    SV* arg;
    // arg may be NULL or may be not
    Sv1 sv1(arg)
    Sv2 sv2 = sv1;

If the arg wasn't NULL, then it's refcounter will be increased twice (on sv1 and sv2 construction), and decreased twice (on sv1 and sv2 destruction). if arg was NULL, then both variables sv1 and sv2 will held NULL SV*. The code above is NULL-safe. However, the following code is NULL-unsafe, i.e. may lead to crashes:

    SV* arg;
    // arg may be NULL or may be not
    Sv1 sv1(arg)
    sv1.payload_attach(&some_payload, &some_marker);

The non-null existance of arg have to checked i.e.

    if (sv1) {
        sv1.payload_attach(&some_payload, &some_marker);

Now this piece of code is safe from crashes at runtime.


When the empty constructor is invoked the Sv variable will be empty, i.e. hold no any perl SV*:

    Sv item;

To let it hold new Perl variable (empty string), it should be constructed via static method create, i.e.:

    auto item = Sv::create();

It is quite common to just wrap underlying Perl C type, the overloaded constructor can be invoked

    Sv (SV* sv, bool policy = INCREMENT)
    Sv (AV* sv, bool policy = INCREMENT)
    Sv (HV* sv, bool policy = INCREMENT)
    Sv (CV* sv, bool policy = INCREMENT)
    Sv (GV* sv, bool policy = INCREMENT)

    AV* av = ...;
    Sv my(av);

The ref-couning policy defines, whether the underlying SV* should be incremented upon Sv object construction; it is true by default. When the Sv goes out of scope, it's destructor will be invoked and the refcounter of the underlying SV* will always be dec-remented.

The construtor does never throws, as all valid SV* values are accepted.

The rule of thumb is following: if Sv wrapper is intended to share ownership with the SV*, it should use INCREMENT policy (this is default, and mostly used case); if the wrapper should own the variable, then the policy should be NONE.

There are convenient static methods to create an Sv wrapper without incrementing the refcounter:

    static Sv noinc (SV* val)
    static Sv noinc (AV* val)
    static Sv noinc (HV* val)
    static Sv noinc (CV* val)
    static Sv noinc (GV* val)

    AV* av = ...;
    auto my = Sv::noinc(av);

The copy and move constructors are provided; the refcounter is not touched:

    Sv (const Sv& oth)
    Sv (Sv&&      oth)

To extract the scalar result of call, it is possible to consturct Sv as:

    Sv (const CallProxy& p)

undef, yes, no

There are a few Sv-constants, which represent common values, e.g. :

    static const Sv undef;
    static const Sv yes;
    static const Sv no;

assignment operators

    Sv& operator= (SV* val)
    Sv& operator= (AV* val)
    Sv& operator= (HV* val)
    Sv& operator= (CV* val)
    Sv& operator= (GV* val)
    Sv& operator= (const CallProxy& p)

    Sv& operator= (const Sv& oth)

The assignment operators are complementaty to the constructors above. As the possible underlying SV* will be thrown away after assignemnt, it's refcounter is dec-remented and the ref-counter of the new value is incremented.

    Sv& operator= (Sv&& oth)

Move-assignment operator is implemented simply by swapping underlying SV* without touching ref-counter.

All assignment operators are NULL-safe


The get the underlying SV* it is possible either to use related coersion operator or dereference operator:

    operator SV*   () const
    SV* operator-> () const

Please note, the result might be nullptr if the underlyging SV* was nullptr.

It is possible to unwrap the underlying SV* either via operator coercion; it is safe and somewhat slower, as in the case of coercion failure the nullptr is returned:

    operator AV*   () const
    operator HV*   () const
    operator CV*   () const
    operator GV*   () const

Or it is possible to do zero-cost typecasting, but without any warranty on type safety or non-nullity:

    template <typename T = SV> one_of_t<T,SV,AV,HV,CV,GV>* get ()

For example:

    AV* av_src = ...;
    Sv sv(av_src);

    AV* av_src = sv;
    if (!av_src) {
        // do something!

    AV* av_src_unsafe = sv.get<AV*>();

To resolve ambiguities in using Sv with Perl macros it the void* coercion operator is supplied:

    operator void* () const

bool operator()

    explicit operator bool () const

Returns true if the Sv wraps any Perl SV*. It is convenient to use in XS-adapters to check whether any value has been supplied in Perl script, e.g.

    void MyClass::my_method(SV* optional1 = nullptr, Sv opt2 = Sv{}) {
        Sv opt1(optional1);
        if (opt1) { ... }
        // a bit more convenient, right?
        if (opt2) { ... }

Please note, that undef is valid perl SV* and it returns true for the operator.


    bool   defined() const

Null-safe method which returns true the object holds any SV* and later is defined.


    bool   is_true        () const

Checks whether the object holds Perl value which evaluates to true. This is NULL-safe method.

type-inspecting methods

    bool   is_scalar      () const
    bool   is_ref         () const
    bool   is_simple      () const
    bool   is_string      () const
    bool   is_like_number () const
    bool   is_array       () const
    bool   is_array_ref   () const
    bool   is_hash        () const
    bool   is_hash_ref    () const
    bool   is_sub         () const
    bool   is_sub_ref     () const
    bool   is_glob        () const
    bool   is_object      () const
    bool   is_object_ref  () const
    bool   is_stash       () const

All the methods above try to guess corresponding SV* type and return true upon successful guess. All the methods are NULL-safe.

    svtype type           () const

This is NULL-unsafe type extraction from from SV*.


readonly(bool val)

    bool   readonly       () const
    void readonly (bool val)

This NULL-unsafe methods examine Perl SV* for read-only flag or set/unset it.


    U32    use_count      () const

Returns refcounter value. If SV* is NULL, then 0 is returned.

upgrade (svtype type)

    void upgrade (svtype type)

Tries to upgrade SV* into the specified type. Exception is thrown if the variable is already marked as readonly or upon attempt to upgrade defined scalar (non-undef) into more than SVt_PVMG.

This is NULL-unsafe method.

dump ()

    void dump () const

Dumps the underlyign SV* to stderr.

reset ()

    void reset ()

Decrements refcounter in the undrerlying SV* and sets it to NULL.

This is NULL-safe method.


    SV* detach ()

Releases ownership on the underlying SV* (which might be NULL) and returns it. The refcounter is not touched.

This is NULL-safe method.

This method is useful when manually returning SV* on perl stack in xs-adapter, e.g.

    void MyClass::method() {
        auto item = new MyClass();
        auto wrapper = xs::out<>(item);

operators ==() and !=()

    operator== (const Sv& lh, const Sv& rh)
    operator!= (const Sv& lh, const Sv& rh)
    operator== (const Sv& lh, SV* rh)
    operator!= (const Sv& lh, SV* rh)
    operator== (SV* lh, const Sv& rh)
    operator!= (SV* lh, const Sv& rh)
    operator== (const Sv& lh, AV* rh)
    operator!= (const Sv& lh, AV* rh)
    operator== (AV* lh, const Sv& rh)
    operator!= (AV* lh, const Sv& rh)
    operator== (const Sv& lh, HV* rh)
    operator!= (const Sv& lh, HV* rh)
    operator== (HV* lh, const Sv& rh)
    operator!= (HV* lh, const Sv& rh)
    operator== (const Sv& lh, CV* rh)
    operator!= (const Sv& lh, CV* rh)
    operator== (CV* lh, const Sv& rh)
    operator!= (CV* lh, const Sv& rh)
    operator== (const Sv& lh, GV* rh)
    operator!= (const Sv& lh, GV* rh)
    operator== (GV* lh, const Sv& rh)
    operator!= (GV* lh, const Sv& rh)

This is group of identity checks operators, i.e. determine whether the underlyging SV* points to the same address as the other argument. As only addresses are compared, all the operations are NULL-safe.

magic payload

Perl gives possibility to attach arbitrary data to SV* via magic slots. The XS::Framework exposes that facility too. To distinguish between different payloads, it is required to supply the per-type unique marker. XS::Framework assumes that it is enough to have just unique address to identiy unique marker. The easiest way to accomplish that is to have:

    static xs::Sv::payload_marker_t my_payload_marker{};

To attach payload the following NULL-unsafe methods can be used:

    MAGIC* payload_attach (void* ptr, Sv obj, const payload_marker_t* marker)
    MAGIC* payload_attach (void* ptr, const payload_marker_t* marker)
    MAGIC* payload_attach (Sv    obj, const payload_marker_t* marker)

The result is perl MAGIC* pointer, which can be safely ignored. To remove magic payload from <SV*> the payload_detach method can be used:

    int payload_detach (payload_marker_t* marker)

To check payload existance via it's market the payload_exists can be used:

    bool payload_exists (const payload_marker_t* marker)

Finally, to get the payload the payload method should be used:

    Payload payload (const payload_marker_t* marker) const

    struct Payload {
        void* ptr;
        SV*   obj;

In the returned Payload struct you should access the ptr or obj, depending on what kind of payload was attached. Both ptr and obj can be used, if both of them were set.

A few words should be told about payload cleanup. If the attached payload type was SV*, then underlying refcounter will be increased, and once magic payload goes of of live, the refcounter will be decremented. However, if arbitrary data was attached as void*, then user-supplied cleanup function will invoked, once it was attached ot the payload marker. The usual place to initialize that custom payload function is BOOT XS-adapter section, for example:

    static xs::Sv::payload_marker_t my_payload_marker{};

    static int my_payload_marker_free(pTHX_ SV*, MAGIC* mg) {
        void* payload = (void*)mg->mg_ptr;
        // place custom clean-up code here.
        return 0;

    BOOT {
        my_payload_marker.svt_free = my_payload_marker_free;

All methods, which work with magic are NULL-unsafe.