Boost logo

Boost Users :

Subject: [Boost-users] [MSM] Unable to retrieve correct value of attribute of a state from within actions. (Possible Bug?)
From: Deniz Bahadir (deniz.bahadir_at_[hidden])
Date: 2013-02-21 15:41:10


Hi everyone,
Hi Christophe,

Using Boost.MSM with eUML I tried to access the attribute of a state
from within an action.
However, the value is not what I expected when accessing the attribute
of the state given as argument to the action. (It seems to be the
default-parameter.) If I access the state directly (by name) and
retrieve the value from it, it is set correctly as expected.

Could it be that an action gets its arguments as copies? If so, I guess,
the attributes of the copied arguments should be copied, too.
This is the case for events. The attributes of an event given to the
action seems to be set correctly.
But the attributes of a state seem to be default-initialized.

For clarification a simple example (this time tested and successfully
compiled):

#include <iostream>
#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/euml/euml.hpp>

using namespace boost::msm::front::euml;
namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace std;

namespace
{

// The attribute:
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int, Number)
BOOST_MSM_EUML_ATTRIBUTES((attributes_ << Number), NumberAttr)
// An event containing the attribute:
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(event1, NumberAttr)
// Two states with attributes:
BOOST_MSM_EUML_STATE((no_action, no_action, attributes_ << Number), state1)
BOOST_MSM_EUML_STATE((no_action, no_action, attributes_ << Number), state2)

// Entry-action which initializes the attributes:
BOOST_MSM_EUML_ACTION(init_events_and_states)
{
   template <class Evt, class Fsm, class State>
   void operator()(Evt const&, Fsm&, State&)
   {
     event1.get_attribute(Number) = 100;
     state1.get_attribute(Number) = 1;
     state2.get_attribute(Number) = 2;
   };
};

// Action that prints the Number-attributes of event and state.
// NOTE: The state-Numbers differ!
BOOST_MSM_EUML_ACTION(printNumber)
{
   template <class Fsm, class Evt,
             class SourceState, class TargetState>
   void operator()(Evt const& evt, Fsm&,
                   SourceState& source, TargetState& target)
   {
     std::cout << "In action \"printNumber\"."
               << "\n event1.Number == " << event1.get_attribute(Number)
               << "\n evt.Number == " << evt.get_attribute(Number)
               << "\n state1.Number == " << state1.get_attribute(Number)
               << "\n source.Number == " << source.get_attribute(Number)
               << "\n state2.Number == " << state2.get_attribute(Number)
               << "\n target.Number == " << target.get_attribute(Number)
               << std::endl;
   };
};

// The transition table:
BOOST_MSM_EUML_TRANSITION_TABLE((
   state1 + event1 / printNumber == state2
), stt)

// The FSM front-end and back-end:
BOOST_MSM_EUML_DECLARE_STATE_MACHINE((
   stt, init_ << state1, init_events_and_states
), FsmFrontend);
typedef msm::back::state_machine<FsmFrontend> Fsm;

void test()
{
     Fsm fsm;
     // needed to start the highest-level FSM.
     // This initializes all attributes.
     fsm.start();
     // emit event1
     fsm.process_event(event1);
}

} // namespace

int main()
{
     test();
     return 0;
}

// This prints the following (except "//") on the cmdline :

// In action "printNumber".
// event1.Number == 100
// evt.Number == 100
// state1.Number == 1
// source.Number == 0
// state2.Number == 2
// target.Number == 0

As you can see, the attribute-values of "event1" and "evt" are the same.
However, the attribute-values of "state1" and "source" differ although
they should be the same, too. (The same applies to "state2" and "target".)

I tried this example with a custom type as attribute-type which prints
each constructor-call and assignment-call and I realized, the
copy-constructor was never called.

If you want to try it yourself, just replace the declaration of the
attribute in the above example with the following code:

class MyInt
{
   int val_;
   public:

   MyInt() : val_(50) { std::cout << "MyInt()" << std::endl; }
   MyInt(const MyInt& obj) : val_(obj.val_) {
     std::cout << "MyInt(const MyInt&) - val_=" << val_ << std::endl;
   }
   MyInt(const int& i) : val_(i) {
     std::cout << "MyInt(const int&) - val_=" << val_ << std::endl;
   }
   MyInt& operator=(const MyInt& obj) {
     val_ = obj.val_;
     std::cout << "op=(const MyInt&) - val_=" << val_ << std::endl;
     return *this;
   }
   MyInt& operator=(const int& i) {
     val_ = i;
     std::cout << "op=(const int&) - val_=" << val_ << std::endl;
     return *this;
   }
};

// The attribute:
BOOST_MSM_EUML_DECLARE_ATTRIBUTE(MyInt, Number)

This looks like a bug, but I am not sure. Maybe I have to write my
transition-table differently?

Ciao,
Deniz

PS: I am using Boost 1.53.0 with GCC 4.7.2 (and C++11 support activated,
most of the time.)


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net