-1

I want to create a list of matrices that I am updating in a loop and return it to R. I have

std::vector<IntegerMatrix> zb_list;

and

IntegerMatrix tb(J,nmax), zb(J,nmax);

before the loop. Inside the loop, I update zb and then have

zb_list.push_back(zb);

I also have

Rcout <<  (zb_list[itr]) << "\n";
Rcout <<  (zb) << "\n\n";

where itr counts the iterations. These both confirm that zb is changing inside the loop and zb_list keeps track of it.

Then I return zb_list after the loop. When accessing the result in R, the list contains copies of the same zb, the last one computed in the loop. I suspect there is some pass by reference going on... but can't figure it out. I don't have a good understanding of what is going on (tried to use return(wrap(zb_list))without luck) but clearly something is wrong. Also used List zb_list; for defining it which doesn't help. Any suggestions?

EDiT: Here is the minimal working example:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
List test_weird(int ITRmax=2) {

  IntegerMatrix  zb(2,2);
  std::vector<IntegerMatrix> zb_list;

  int itr = 0;
  while (itr < ITRmax) {

   zb( (1+itr)%2 ,(1+itr)%2 ) ++ ;
   zb_list.push_back(zb);


   Rcout << (zb) <<   (zb_list[itr]) << "\n\n";
    ++itr; 
  }

  return List::create(_["zb"] = zb,
                      _["zb_list"] = zb_list);
}


/*** R
res <- test_weird()
res$zb_list
*/

This the output when the look is running:

0 0
0 1
0 0
0 1


1 0
0 1
1 0
0 1

... and this is the output from R:

> res$zb_list
[[1]]
     [,1] [,2]
[1,]    1    0
[2,]    0    1

[[2]]
     [,1] [,2]
[1,]    1    0
[2,]    0    1

As you can see both items in the list are the last zb in the loop.

passerby51
  • 835
  • 2
  • 9
  • 23

1 Answers1

1

The problem is that push_back(something) makes a copy of something. But if something is a pointer, than subsequent changes will effect all copies of that pointer. In plain C++:

#include <vector>
#include <iostream>

int main() {
  std::vector<int*> v;
  int* p = new int; 
  for (int i = 0; i < 2; ++i) {
    *p = i;
    v.push_back(p);
    std::cout << *p << " " << *v[i] << std::endl;
  }
  std::cout << *v[0] << " " << *v[1] << std::endl;
  return 0;
}

produces

$ ./pointer_fun 
0 0
1 1
1 1

So if the something is a pointer (like object), which is the case for all Rcpp objects, then you need a deep copy/clone of the object, i.e.

zb_list.push_back(clone(zb));
Ralf Stubner
  • 26,263
  • 3
  • 40
  • 75