On Wed, 17 May 2006, Michael Dondrup wrote: > Hi, > > Im currently trying to debug a 'error in unprotect: stack imbalance' problem > and I am curious about two basic questions on the use of PROTECT and > UNPROTECT, which I could not figure out: > > - which objects have to be protected, namely, if the code is something like: > > SEXP fun, e; > /* get the expression e ... */ > fun = eval(e, R_GlobalEnv); > /* or like this?: PROTECT(fun = eval(e, R_GlobalEnv)); */ > PROTECT(fun = VECTOR_ELT(fun, 1)); > /* do more things with fun ... */ > > does one need to protect the result of a call to 'eval' immediately? And how > about R_tryEval? > While searching for code examples in the sources, I found both protected evals > and fewer non-protected.
The first rule is that any newly created R object needs to be protected before the garbage collector runs, and unprotected before exiting the function and after the last time the garbage collector runs. The second rule is that protection applies to the contents of a variable (the R object) not to the variable. The second rule is that protecting an object protects all its elements. In the example above fun = eval(e, R_GlobalEnv); may create a new object (it might just return a pointer to an existing function) and so probably needs to be protected. On the other hand fun = VECTOR_ELT(fun, 1); does not then need protecting. Since fun is protected, its second element is also protected. So PROTECT(fun = eval(e, R_GlobalEnv)); fun = VECTOR_ELT(fun, 1); /* do more stuff with fun */ UNPROTECT(1); If you don't know exactly which functions might return a new object or trigger the garbage collector it is probably safe to assume that anything might [this is the advice in 'Writing R Extensiosn']. Unless you are getting close to the limits of the pointer protection stack (eg in recursive algorithms), you might be safer writing code like PROTECT(fun = eval(e, R_GlobalEnv)); PROTECT(fun = VECTOR_ELT(fun, 1)); /* do more stuff with fun */ UNPROTECT(2); but I think it is useful to know that the vector accessors and mutators do not allocate memory. A stack imbalance is often due to different numbers of PROTECTs on different code paths. These are slightly annoying and become more frequent if you use more PROTECTs. On the other hand, R does detect them for you. If you don't use enough PROTECTs you get bugs that are very hard to track down [the best bet is probably valgrind + gctorture() to provoke them into showing themselves early, but that's only available on Linux]. -thomas ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel