@@ -36,4 +36,53 @@ context("external_pointer-C++") {
3636 uniq.reset ();
3737 expect_true (deleted == true );
3838 }
39+
40+ test_that (" external_pointer preserves attributes when moved (issue #308)" ) {
41+ // Test move constructor
42+ {
43+ int * value = new int (42 );
44+ cpp11::external_pointer<int > p (value);
45+
46+ // Set an attribute on the external pointer
47+ Rf_setAttrib (p, R_ClassSymbol, Rf_mkString (" test_class" ));
48+
49+ // Verify attribute exists before move
50+ SEXP class_attr = Rf_getAttrib (p, R_ClassSymbol);
51+ expect_true (class_attr != R_NilValue);
52+
53+ // Move the external pointer using move constructor
54+ cpp11::external_pointer<int > p_moved = std::move (p);
55+
56+ // Verify attribute is preserved after move
57+ SEXP class_attr_after = Rf_getAttrib (p_moved, R_ClassSymbol);
58+ expect_true (class_attr_after != R_NilValue);
59+ expect_true (strcmp (CHAR (STRING_ELT (class_attr_after, 0 )), " test_class" ) == 0 );
60+
61+ // Clean up
62+ delete p_moved.release ();
63+ }
64+
65+ // Test move assignment operator
66+ {
67+ int * value1 = new int (1 );
68+ cpp11::external_pointer<int > p1 (value1);
69+
70+ // Set an attribute on p1
71+ Rf_setAttrib (p1, R_ClassSymbol, Rf_mkString (" test_class" ));
72+
73+ // Create p2 with nullptr (no memory leak)
74+ cpp11::external_pointer<int > p2 (nullptr );
75+
76+ // Move assign p1 to p2
77+ p2 = std::move (p1);
78+
79+ // Verify attribute is preserved after move assignment
80+ SEXP class_attr_after = Rf_getAttrib (p2, R_ClassSymbol);
81+ expect_true (class_attr_after != R_NilValue);
82+ expect_true (strcmp (CHAR (STRING_ELT (class_attr_after, 0 )), " test_class" ) == 0 );
83+
84+ // Clean up
85+ delete p2.release ();
86+ }
87+ }
3988}
0 commit comments