Dimension error with `r_vector`
Hi, thanks for this wonderful package. As I was playing around with the r_vector class, I found the following peculiar behavior and I think this might be a bug. Specifically, there should only be 6 elements, but when writing the dimensions to the vector, it returns an error saying there's 8 elements.
cpp11::cpp_function(
"
SEXP test() {
using namespace cpp11;
writable::r_vector<double> vec; // Start empty
// Dynamically add data
vec.push_back(1.0);
vec.push_back(2.0);
vec.push_back(3.0);
vec.push_back(4.0);
vec.push_back(5.0);
vec.push_back(6.0);
message(\"size: %i\", vec.size());
// Now decide dimensions (2 rows by 3 columns)
vec.attr(R_DimSymbol) = writable::r_vector<int>({2, 3});
// Create matrix from the vector
// writable::doubles_matrix<> mat(vec.data());
return(vec.attr(R_DimSymbol));
}
"
)
test()
#> size: 6
#> Error in test(): dims [product 6] do not match the length of object [8]
Created on 2025-07-21 with reprex v2.1.1
Disclaimer: This example was taken from some code snippets from Claude while I was trying to understand the internals of this package.
hi @fangzhou-xie
When you set attributes on an R vector, R "sees" the underlying SEXP which has full capacity (8 elements), not just the length (6 elements) that you've actually used. This explains the behaviour: https://github.com/r-lib/cpp11/blob/main/inst/include/cpp11/r_vector.hpp#L1058
The "correct" way would be copy the object as a SEXP:
SEXP test() {
using namespace cpp11;
writable::r_vector<double> vec;
vec.push_back(1.0);
vec.push_back(2.0);
vec.push_back(3.0);
vec.push_back(4.0);
vec.push_back(5.0);
vec.push_back(6.0);
SEXP vec_sexp = vec;
Rf_setAttrib(vec_sexp, R_DimSymbol, writable::r_vector<int>({2, 3}));
return vec_sexp;
}
or to avoid copies to be explicit with the resize:
SEXP test() {
using namespace cpp11;
writable::r_vector<double> vec;
vec.push_back(1.0);
vec.push_back(2.0);
vec.push_back(3.0);
vec.push_back(4.0);
vec.push_back(5.0);
vec.push_back(6.0);
// Explicitly resize to current length (truncates capacity)
vec.resize(vec.size());
vec.attr(R_DimSymbol) = writable::r_vector<int>({2, 3});
return vec;
}