Skip to content

Commit

Permalink
Return a zero length vector default constructed are converted to SEXP
Browse files Browse the repository at this point in the history
When we default construct writable vectors we set them to R_Nilvalue, so
the default constructor cannot throw an exception. However this causes
problems if you then immediately return them. By checking for this
condition in the SEXP conversion function we can return a 0 length
vector in these cases, which is what the user likely intended.

Fixes #166
  • Loading branch information
jimhester committed Sep 16, 2021
1 parent 6f4fbe3 commit f286cf5
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 1 deletion.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# cpp11 (development version)

* `writable::r_vector` default constructors now return a 0 length vector when converted to `SEXP` (#166)
* read-only `r_vector` constructors now disallow implicit construction with named arguments (#237)
* read-only `r_vector.attr()` methods now return const objects, so it is a compile time error to try to assign to them (#237)
* Allow `cpp11::matrix` to be accessed either row-wise or column-wise (the default) depending on the user's choice (@alyst, #229)
Expand Down
8 changes: 8 additions & 0 deletions cpp11test/src/test-list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,12 @@ context("list-C++") {
cpp11::strings nms(x.names());
expect_true(x.size() == nms.size());
}

test_that("We don't return NULL for default constructed vectors") {
cpp11::writable::list x;
SEXP y(x);

expect_true(Rf_xlength(y) == 0);
expect_true(y != R_NilValue);
}
}
6 changes: 5 additions & 1 deletion inst/include/cpp11/r_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -900,8 +900,12 @@ inline SEXP truncate(SEXP x, R_xlen_t length, R_xlen_t capacity) {

template <typename T>
inline r_vector<T>::operator SEXP() const {
auto* p = const_cast<r_vector<T>*>(this);
if (data_ == R_NilValue) {
p->resize(0);
return data_;
}
if (length_ < capacity_) {
auto* p = const_cast<r_vector<T>*>(this);
p->data_ = truncate(p->data_, length_, capacity_);
SEXP nms = names();
auto nms_size = Rf_xlength(nms);
Expand Down

0 comments on commit f286cf5

Please sign in to comment.