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。在此处发布编译器标志会有所帮助。