Skip to content

Commit 2f03363

Browse files
committed
make finalize() a no-op for never-constructed module objects
An object created without arguments for a class without a default constructor holds the dummy pointer, which is an environment rather than an external pointer. Its finalize() method passed it to CppObject__finalize, which failed, and the failure surfaced as "Expecting an external pointer: [type=environment]" during garbage collection.
1 parent 2cf7685 commit 2f03363

3 files changed

Lines changed: 22 additions & 3 deletions

File tree

‎ChangeLog‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
2026-10-22 Kevin Ushey <kevinushey@gmail.com>
2+
3+
* R/Module.R (cpp_refMethods): Make finalize() a no-op for a module
4+
object that was never constructed (created without arguments for a class
5+
without a default constructor); it used to fail on the dummy pointer, and
6+
the failure surfaced as an error message at garbage collection
7+
* inst/tinytest/test_module.R: Add test
8+
19
2026-10-22 Michael Sumner <mdsumner@gmail.com>
210

311
* R/00_classes.R: Define C++Field, C++OverloadedMethods and C++Constructor

‎R/Module.R‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,14 +400,18 @@ method_wrapper <- function( METHOD, where ){
400400
## create a named list of the R methods to invoke C++ methods
401401
## from the C++ class with pointer xp
402402
cpp_refMethods <- function(CLASS, where) {
403+
# an object created without arguments for a class lacking a default
404+
# constructor holds the dummy pointer (see cpp_object_dummy), which is
405+
# not an external pointer: there is nothing to finalize for it
403406
finalizer <- eval( substitute(
404407
function(){
405-
.Call( CppObject__finalize, class_pointer , .pointer )
408+
if( ! identical( .pointer, dummy ) )
409+
.Call( CppObject__finalize, class_pointer , .pointer )
406410
},
407411
list(
408-
CLASS = CLASS@pointer,
409412
CppObject__finalize = CppObject__finalize,
410-
class_pointer = CLASS@pointer
413+
class_pointer = CLASS@pointer,
414+
dummy = .dummyInstancePointer
411415
)
412416
) )
413417
mets <- c(

‎inst/tinytest/test_module.R‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,10 @@ gctorture(TRUE)
123123
res <- gadget$value()
124124
gctorture(FALSE)
125125
expect_identical( res, c(1, 2, 3) )
126+
127+
# test.Module.finalize.dummy <- function(){
128+
## an object created without arguments for a class lacking a default
129+
## constructor holds the dummy pointer; finalizing it must be a no-op
130+
## rather than an error (which used to surface at garbage collection)
131+
r <- new( ModuleRandomizer )
132+
expect_identical( r$finalize(), NULL )

0 commit comments

Comments
 (0)