artemonster artemonster - 8 days ago 7
C++ Question

cout overwrites some of my pointers

I have a strange problem where a simple cout messes up my previously defined pointers. Here is the code:

union Value {
bool a;
long long val;
int next;
};

struct Clos { //not a "closure" in its actual sense.
vector<Value**> args;
function<void()> method;
};

Clos* prepare() {
Clos* closure = new Clos();

Value* a = nullptr; //these values do not exist yet, but I need these pointers to rename them at RT
Value* b = nullptr;
Value* out = new Value; //this exists
closure->args.push_back(&a); //save adresses to rename them later
closure->args.push_back(&b);
closure->method = [&a, &b, &out](){out->val = a->val + b->val;}; //just some operation on arguments
return closure;
}


Here I create an object "closure" with bound function (a "method") that uses not-yet-defined pointers as arguments, which will be bound later at runtime.

Later:

int main(void) {
Clos* clos = prepare();
Value a; //now we get input values at RT
a.val = 7;
Value b;
b.val = 8;
*clos->args[0] = &a; //we bind them to previously "dangling" pointers
*clos->args[1] = &b;
cout << "WOLOLOLOLO"; //<<<<---- COMMENT OUT THIS LINE AND BOOM!
clos->method(); //this works, as long cout is not called
}


Is there a problem with how I initially define a and b (as nullpointers?) Do they get deallocated or something? I've tried making them "static" but it does not work either. Something is wrong on general level :(

Answer

The main issue is here:

closure->method = [&a, &b, &out](){out->val = a->val + b->val;};

This lambda is creating a closure which references local variables. This closure is no longer callable once the variables go out of scope. I think you want something more like this:

#include <vector>
#include <iostream>
#include <functional>

using std::vector;
using std::function;
using std::cout;


union Value {
  bool a;
  long long val;
  int next;
};

struct Clos { //not a "closure" in its actual sense.
  vector<Value*> args;
  function<void()> method;

  ~Clos()
  {
    for (auto &arg : args) {
      delete arg;
    }
  }
};

Clos* prepare() {
  Clos* closure = new Clos();

  Value* a = new Value;
  Value* b = new Value;
  Value* out = new Value; //this exists
  closure->args.push_back(a);
  closure->args.push_back(b);
  closure->args.push_back(out);

  // Make copies of the pointers, not references.
  closure->method = [a, b, out](){out->val = a->val + b->val;};

  return closure;
}

int main(void) {
  Clos* clos = prepare();
  Value a; a.val = 7;
  Value b; b.val = 8;
  *clos->args[0] = a;
  *clos->args[1] = b;
  clos->method();
  cout << clos->args[2]->val << "\n";

  delete clos;
}
Comments