Linux上std::map的内存对齐问题 我在用C++处理Linux时遇到了问题。< /P>

Linux上std::map的内存对齐问题 我在用C++处理Linux时遇到了问题。< /P>,c++,memory,alignment,C++,Memory,Alignment,我有一个基本消息类,如下所示: class MsgBase { public: MsgBase( unsigned int msgid ); map < unsigned int, MSGIEBase* > messageIE_Map; // map for IEs unsigned int messageId; // 32 bit message id }; 这里的MSGIE_UINT32和MSGIE_String是从MSG

我有一个基本消息类,如下所示:

class MsgBase
{
    public:
        MsgBase( unsigned int msgid );
        map < unsigned int, MSGIEBase* > messageIE_Map; // map for IEs
        unsigned int messageId; // 32 bit message id
};
这里的MSGIE_UINT32和MSGIE_String是从MSGIEBase派生的类,因此它们的地址可以存储在上面的基类中定义的映射中。 构造Der1时,ueId和configFileName的地址存储在映射中。 在这里,如果我打印地图的大小(通过gdb并在程序中),它将是24。 [_M_header=16,_M_node_count=4,_M_key_compare=1,我想是3字节填充]

直到这里一切都好。现在,将Der1对象指针放在事件对象中,并将事件发布到队列中。事件类如下所示:

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

        // IEs
        MSGIE_UINT32 ueId;
        MSGIE_String configFileName;
};
class Event 
{
   public:
       MsgBase* msgPtr;
};
另一个线程从队列中删除事件,提取msgPtr并将其转换为Der1指针,这就是问题的开始

这里,如果我在程序中打印地图的大小,它是21。这意味着MsgBase类中下一个成员的地址,即messageId被移位了3个字节,因此messageId的值完全改变。(通过gdb查看时,地址仍然完整,地图大小也保持不变,即24)


就我所知,这是一个单词对齐问题,但为什么在不同的函数中内存对齐不一致,为什么在使用new分配给类的内存时,类成员的地址会发生变化。我正在使用Linux 2.6.27,gcc版本4.1.1,RHEL-4.

要排除非虚拟析构函数/复制/分配问题,请将以下内容添加到
MsgBase

public:
    virtual ~MsgBase();
private:
    MsgBase(MsgBase const& other);
    MsgBase& operator=(MsgBase const& other);

我将尝试逐步提供所有必需的信息:

信息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

}
//步骤1:创建消息并填写消息Id
MsgBase*msgPtr=new-Der1();
//Der1的任务大纲如下:
Der1::Der1()
:MsgBase(ATS_SUTD_EPCTESTER_ATTACH_SCENARIO_MsgId),//MsgId是13(0xd)
ueId(即“UE”键,“UE”,假),
configFileName(即配置文件名密钥,“配置文件名”,false)
{
//在地图中插入IEs
this->addIEEntry(即,&ueId);//这会将条目放入映射中
此->添加尝试(即配置文件名、密钥和配置文件名);
}
//步骤2:声明事件并发布事件
事件*事件=新事件(事件ID,“事件”);
事件->设置数据(msgPtr、hdr);
//在此阶段检查消息id(
cout eventQueueMutex.acquireLock();
此->事件队列。推回(ev);
此->eventQueueMutex.releaseLock();
//向调度程序提交作业
bool status=JobScheduler::getInstance()->scheduleJob(此);
返回状态;
}
//事件类是
类事件:公共事件库
{
公众:
事件();
虚拟事件();
事件(int evId);
事件(int evId、字符串evName);
MsgBase*getMessagePtr();
无效设置数据(MsgBase*mPtr,表头*hPtr)
私人:
//防止复制
事件和操作员=(事件和ev);
事件(事件和evBase);
MsgBase*msgPtr;
标题*hdrPtr;
};
void事件::setData(MsgBase*mPtr,Header*hPtr)
{
此->msgPtr=mPtr;
本->hdrPtr=hPtr;
}
步骤3:提取事件并重新打印消息Id
//从队列中提取数据的代码如下所示:
void AppClass::进程()
{
EventBase*beventPtr=NULL;
此->eventQueueMutex.acquireLock();
如果(!this->eventQueue.empty())
{
beventPtr=(EventBase*)(this->eventQueue.front());
此->eventQueue.pop_front();
}
其他的
{
isQueueEmpty=true;
}
此->eventQueueMutex.releaseLock();
事件*eventPtr=(事件*)beventPtr;
Der1*msgPtr=(Der1*)(eventPtr->getMessagePtr());

cout取决于您如何操作这些对象。显示您的代码。(我不认为这是内存对齐问题)我认为您对映射大小和内存对齐的假设使您走上了错误的道路。您从未解释实际问题,只是我认为不相关的症状。发生了什么(错误的)当你从队列中弹出时,在你的程序中?我认为此时源代码的推送和弹出部分会更相关,我猜这是一个问题。有实际问题吗?向我们展示一些相关的代码。你对这两个文件使用相同的编译选项吗?
sizeof(std::map)
只有在使用一些不应该正常使用的奇怪编译器选项和/或杂注时,才可以等于21。在此处发布编译器标志会有所帮助。