Проблема выравнивания памяти с std :: map в Linux - PullRequest
1 голос
/ 14 августа 2011

Я столкнулся с проблемой при работе с c ++ над Linux.

У меня есть базовый класс Message, который выглядит следующим образом:

class MsgBase
{
    public:
        MsgBase( unsigned int msgid );
        map < unsigned int, MSGIEBase* > messageIE_Map; // map for IEs
        unsigned int messageId; // 32 bit message id
};

класс Der1 является производным от MsgBase и выглядитнапример:

class Der1 : public MsgBase
{
    public:
        Der1 ();
        virtual ~Der1 ();

        // IEs
        MSGIE_UINT32 ueId;
        MSGIE_String configFileName;
};

Здесь MSGIE_UINT32 и MSGIE_String являются классами, производными от MSGIEBase, и поэтому их адрес может быть сохранен в карте, определенной в базовом классе выше.Когда Der1 создан, адрес ueId и configFileName сохраняется на карте.Здесь, если я напечатаю размер карты (через gdb и в программе), он будет равен 24. [_M_header = 16, _M_node_count = 4, _M_key_compare = 1, 3 байта, я полагаю].

До здесьВсе отлично.Теперь указатель объекта Der1 помещается внутри объекта события, а событие отправляется в очередь.Класс события выглядит следующим образом:

class Event 
{
   public:
       MsgBase* msgPtr;
};

Другой поток удаляет событие из очереди, извлекает msgPtr и помещает его в указатель Der1, и именно здесь начинается проблема.

Здесь, еслиЯ печатаю размер карты в программе, равный 21. Это означает, что адрес следующего члена в классе MsgBase, т.е. messageId, сдвигается на 3 байта, и поэтому значение messageId изменяется полностью.(при просмотре через gdb адрес все еще остается неизменным, как и размер карты, т. е. 24).

Насколько мне известно, это вопрос выравнивания слов, но почему выравнивание памяти не согласовано вразличные функции и почему адрес члена класса chage, когда память для класса была выделена с помощью new.Я использую Linux 2.6.27., версия gcc 4.1.1., RHEL-4.

Ответы [ 2 ]

1 голос
/ 15 августа 2011

Для исключения не виртуальных проблем с деструктором / копированием / назначением добавьте следующее к MsgBase:

public:
    virtual ~MsgBase();
private:
    MsgBase(MsgBase const& other);
    MsgBase& operator=(MsgBase const& other);
0 голосов
/ 15 августа 2011

Я постараюсь предоставить всю необходимую информацию шаг за шагом:

Информация 1: соответствующий код.

//Step 1:  Create msg and fill message Id
MsgBase*msgPtr = new Der1();

// C'tor of Der1 is as follows:
Der1::Der1 ()
          : MsgBase ( ATS_SUTD_EPCTESTER_ATTACH_SCENARIO_MsgId ), // msgid is 13( 0xd )
            ueId ( IE_UE_KEY, "UE", false ),
            configFileName ( IE_CONFIG_FILE_NAME_KEY, "Configuration File Name", false )
{
            // Insert the IEs in the map
this->addIEEntry ( IE_UE_KEY, &ueId ); // this puts entries in the map
this->addIEEntry ( IE_CONFIG_FILE_NAME_KEY, &configFileName );
}

// Step 2: Declare event and post the event
Event* event = new Event ( eventId, "Event" );
event->setData( msgPtr, hdr);

// check the message id at this stage ( 
cout << "msgId  = " << ( ( (Der1* )msgPtr )->messageId )<< endl; // Here it comes out 
                                                          // to be 0xd which is correct

// post the event
AppClass::getInstance()->addEventAndSchedule ( event );

//The queue is a member of AppClass and  has been defined as 
std::list <EventBase* > eventQueue;

// The code which inserts data into the queue is as follows:
bool AppClass::addEventAndSchedule ( EventBase* ev )
{
   if ( ev == NULL ) return false;
   this->eventQueueMutex.acquireLock();
   this->eventQueue.push_back( ev );
   this->eventQueueMutex.releaseLock();

   // Submit Job to Scheduler
   bool status = JobScheduler::getInstance()->scheduleJob( this );
   return status;
}

// The event class is
class Event: public EventBase
{
  public:
  Event ();
  virtual ~Event ();
  Event ( int evId );
  Event ( int evId, string evName );
  MsgBase* getMessagePtr ();
  void setData ( MsgBase*  mPtr, Header* hPtr )

  private:
   // Prevent copying
   Event& operator= ( Event& ev );
   Event ( Event& evBase );

   MsgBase* msgPtr;
   Header*    hdrPtr;
};

void Event::setData ( MsgBase* mPtr,  Header* hPtr )
{
   this->msgPtr = mPtr;
   this->hdrPtr =  hPtr;
}


Step 3 : Extract the event and re-print the message Id
// The code which extracts data from the queue is as follows:
void AppClass::process ()
{
               EventBase* beventPtr = NULL;
               this->eventQueueMutex.acquireLock();

    if ( !this->eventQueue.empty() )
    {
       beventPtr  = (EventBase* )( this->eventQueue.front() );
       this->eventQueue.pop_front();
    }
    else
    {
        isQueueEmpty = true;
    }

    this->eventQueueMutex.releaseLock();
    Event* eventPtr = ( Event* )beventPtr ;

                             Der1* msgPtr = (Der1* )( eventPtr->getMessagePtr()) ;
     cout << "msgId  = " <<  msgPtr->messageId << endl;  // This value
             //comes out to be incorrect it is now 0xd000000  i.e. a 3 byte shift

}

Информация 2: Точная проблема. Точная проблема заключается в том, что «messasgeId» меняется при переходе. Первоначально это 0xd, но после выхода из очереди оно становится 0xd000000. Из-за этого вся обработка останавливается. Адрес этого параметра также изменяется с 0x82bd7cc до 0x82bd7c9 при печати в программе. Однако, как видно из GDB, он по-прежнему равен 0x82bd7cc, а значение по-прежнему равно 0xd.

Информация 3: Флаги компилятора. Флаги компилятора одинаковы для всех файлов: -O0 -g3 -Wall -fmessage-length = 0

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...