Home > Enterprise >  saving a lambda expression as parameter/variable inside a class to another class
saving a lambda expression as parameter/variable inside a class to another class

Time:12-02

I made a class and a struct.

The class is named Learning and the struct is named Action.

My Action constructor takes two parameters: object's name and function, where the name is basically a std::string and the function is a std::function<int(int)>.

This is my Action struct:

typedef std::function<int(int)> func;

struct Action {
    // constructor
    Action(name, const func&);

    /// methods
    void setname(name);
    void setfunction(const func&);
    /// operators
    int operator()(int x);

    /// members
    name ActionName;
    func f;
};

My Action struct is used by my Learning class by calling this function:

Learning robot;
robot.addAction(Action("Up", [](int y) ->int{return y  ; }));

Where the Action is saved inside an actions vector in my Learning class:

class Learning
{
public:
    void addAction(Action&);
private:
    std::vector<Action> actions;
};

void Learning::addAction(Action& act)
{
    actions.push_back(act);
}

The method addAction() adds the created Action object into my actions vector.

I used a lambda expression as the parameter because it looks cleaner.

But when I call actions[0].f(0), or actions[0](0), I get an exception:

Unhandled exception at 0x00007FFA4DE44F69 in RL_Q.exe: Microsoft C   exception: std::bad_function_call at memory location 0x000000C09A7BE4C0.

this is my Action constructor

Action::Action(name name, func f) { setname(name); setfunction(f); } 

When I debug this, my function f is empty after I instantiate my Action object with given parameters.

How do I solve this?

CodePudding user response:

Your addAction method takes a reference

void addAction(Action&);

Then you call this with an rvalue

robot.addAction(Action("Up", [](int y) ->int{return y  ; }));

You can not bind an rvalue to a non-const lvalue reference. Either make the method const ref or rvalue reference.

void addAction(const Action&);
void addAction(Action&&);

CodePudding user response:

You define

Learning::addAction(Action&) 

with an action reference as argument. This means that you have to ensure the lifetime of the referenced object, and not let it get destroyed by going out of scope. But then you call it on an rvalue

// Action(...) immediately goes out of scope
robot.addAction(Action("Up", [](int y) ->int{return y  ; }));

Therefore the references you put in your vectors are all invalid : they point toward long gone objects. You need to take ownership of them if you want it to work. This means :

class Learning
{  
  public:
    void addAction(Action&&);
  private:
    std::vector<Action> actions;
};

// rvalue reference, so the vector can take ownership of the expiring object
void Learning::addAction(Action&& act)
{
  actions.push_back(std::move(act));
}
  • Related