首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Linux上std::map的内存对齐问题

Linux上std::map的内存对齐问题
EN

Stack Overflow用户
提问于 2011-08-15 00:35:09
回答 2查看 426关注 0票数 0

在Linux上使用c++时,我遇到了一个问题。

我有一个基本的Message类,如下所示:

代码语言:javascript
复制
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派生而来,如下所示:

代码语言:javascript
复制
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对象指针被放在一个事件对象中,事件被post到一个队列中。事件类如下所示:

代码语言:javascript
复制
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。

EN

回答 2

Stack Overflow用户

发布于 2011-08-15 04:54:48

为了排除非虚拟析构函数/复制/赋值问题,请在MsgBase中添加以下内容

代码语言:javascript
复制
public:
    virtual ~MsgBase();
private:
    MsgBase(MsgBase const& other);
    MsgBase& operator=(MsgBase const& other);
票数 1
EN

Stack Overflow用户

发布于 2011-08-15 07:42:19

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

信息1:相关代码。

代码语言:javascript
复制
//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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7058127

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档