$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
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.)