Safe to UNPROTECT() when object is assigned to a list?

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Safe to UNPROTECT() when object is assigned to a list?

Henrik Bengtsson-2
Hi,

I'm troubleshooting some native code on Windows that very occationally
(and semi-randomly) crashes R.  Already looked at "everything", I just
want to double check that it is safe to UNPROTECT() allocated
variables as soon as they are assigned to, say, a PROTECTed list.

>From (R v2.3.0) Section 5.7.1 "Handling the effects of garbage
collection" in "Writing R Extensions":

"In some cases it is necessary to keep better track of whether
protection is really needed. Be particularly aware of situations where
a large number of objects are generated. The pointer protection stack
has a fixed size (default 10,000) and can become full. It is not a
good idea then to just PROTECT everything in sight and UNPROTECT
several thousand objects at the end. It will almost invariably
possible to either assign the objects as part of another object (which
automatically protects them) or unprotect them immediately after use."

BTW, should it say "...another [protected] object..."?

Example from "5.7.4 Attributes" illustrating my question:

     SEXP out(SEXP x, SEXP y)
     {
       R_len_t i, j, nx, ny;
       double tmp;
       SEXP ans, dim, dimnames;

       nx = length(x); ny = length(y);
       PROTECT(ans = allocVector(REALSXP, nx*ny));
       for(i = 0; i < nx; i++) {
         tmp = REAL(x)[i];
         for(j = 0; j < ny; j++)
           REAL(ans)[i + nx*j] = tmp * REAL(y)[j];
       }

       PROTECT(dim = allocVector(INTSXP, 2));
       INTEGER(dim)[0] = nx; INTEGER(dim)[1] = ny;
       setAttrib(ans, R_DimSymbol, dim);

       *** It is safe to do UNPROTECT(1) for 'dim' already here, correct? ***

       PROTECT(dimnames = allocVector(VECSXP, 2));
       SET_VECTOR_ELT(dimnames, 0, getAttrib(x, R_NamesSymbol));
       SET_VECTOR_ELT(dimnames, 1, getAttrib(y, R_NamesSymbol));
       setAttrib(ans, R_DimNamesSymbol, dimnames);

       UNPROTECT(3);
       return(ans);
     }

Thanks

/Henrik

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: Safe to UNPROTECT() when object is assigned to a list?

Peter Dalgaard
"Henrik Bengtsson" <[hidden email]> writes:

> Hi,
>
> I'm troubleshooting some native code on Windows that very occationally
> (and semi-randomly) crashes R.  Already looked at "everything", I just
> want to double check that it is safe to UNPROTECT() allocated
> variables as soon as they are assigned to, say, a PROTECTed list.
>
> >From (R v2.3.0) Section 5.7.1 "Handling the effects of garbage
> collection" in "Writing R Extensions":
>
> "In some cases it is necessary to keep better track of whether
> protection is really needed. Be particularly aware of situations where
> a large number of objects are generated. The pointer protection stack
> has a fixed size (default 10,000) and can become full. It is not a
> good idea then to just PROTECT everything in sight and UNPROTECT
> several thousand objects at the end. It will almost invariably
> possible to either assign the objects as part of another object (which
> automatically protects them) or unprotect them immediately after use."
>
> BTW, should it say "...another [protected] object..."?

Yes. (And the text could need general rephrasing too. I'm afraid that
I'm the guilty party.)

 

> Example from "5.7.4 Attributes" illustrating my question:
>
>      SEXP out(SEXP x, SEXP y)
>      {
>        R_len_t i, j, nx, ny;
>        double tmp;
>        SEXP ans, dim, dimnames;
>
>        nx = length(x); ny = length(y);
>        PROTECT(ans = allocVector(REALSXP, nx*ny));
>        for(i = 0; i < nx; i++) {
>          tmp = REAL(x)[i];
>          for(j = 0; j < ny; j++)
>            REAL(ans)[i + nx*j] = tmp * REAL(y)[j];
>        }
>
>        PROTECT(dim = allocVector(INTSXP, 2));
>        INTEGER(dim)[0] = nx; INTEGER(dim)[1] = ny;
>        setAttrib(ans, R_DimSymbol, dim);
>
>        *** It is safe to do UNPROTECT(1) for 'dim' already here, correct? ***

Yes. The protection of "ans" will carry over to its attributes.

>        PROTECT(dimnames = allocVector(VECSXP, 2));
>        SET_VECTOR_ELT(dimnames, 0, getAttrib(x, R_NamesSymbol));
>        SET_VECTOR_ELT(dimnames, 1, getAttrib(y, R_NamesSymbol));
>        setAttrib(ans, R_DimNamesSymbol, dimnames);
>
>        UNPROTECT(3);
>        return(ans);
>      }
>
> Thanks
>
> /Henrik
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

--
   O__  ---- Peter Dalgaard             Ă˜ster Farimagsgade 5, Entr.B
  c/ /'_ --- Dept. of Biostatistics     PO Box 2099, 1014 Cph. K
 (*) \(*) -- University of Copenhagen   Denmark          Ph:  (+45) 35327918
~~~~~~~~~~ - ([hidden email])                  FAX: (+45) 35327907

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel