r-lib / cpp11

cpp11 helps you to interact with R objects using C++ code.
https://cpp11.r-lib.org/
Other
199 stars 46 forks source link

External pointers and attributes #308

Open krlmlr opened 1 year ago

krlmlr commented 1 year ago

Invoking the move constructor of external_pointer<> clears attributes on an external pointer object.

I would expect the third and fourth output to be identical to the second output. A possible fix is https://github.com/duckdb/duckdb/pull/6526/commits/12f6f10c12edda4d1153777d7a172279be11191c (this project uses a vendored version of cpp11).

library(cpp11)

cpp_source(
  code = '
  #include "cpp11/external_pointer.hpp"
  #include "cpp11/strings.hpp"

  template <class X>
  cpp11::external_pointer<int> test_int() {
    X a = 0;
    auto p = cpp11::external_pointer<X>(&a, false);
    Rf_PrintValue(p);
    Rf_setAttrib(p, R_ClassSymbol, cpp11::writable::strings({"foo"}));
    Rf_PrintValue(p);

    return std::move(p);
  }

  [[cpp11::register]]
  SEXP test() {
    auto p = cpp11::sexp(test_int<int>());
    Rf_PrintValue(p);
    return p;
  }
  '
)

out <- test()
#> <pointer: 0x16f0af42c>
#> <pointer: 0x16f0af42c>
#> attr(,"class")
#> [1] "foo"
#> <pointer: 0x16f0af42c>
out
#> <pointer: 0x16f0af42c>

Created on 2023-03-02 with reprex v2.0.2

stephematician commented 1 year ago

In addition - there's some strange behaviour/errors that I couldn't pin down while moving duplicated external pointers around, e.g.

#include "cpp11.hpp"

using namespace cpp11;

[[cpp11::register]]
void cpp_death() {
    external_pointer<int> value_xptr(new int [8]);
    external_pointer<int> duplicate_xptr(value_xptr);
    value_xptr = std::move(duplicate_xptr);
}

It could be because external_pointer::r_deleter is called on the old_data (in external_pointer::reset) regardless of whether it should be called or not (I would have thought that r_deleter calls were managed by R when it finalised an EXTPTRSXP).