我在使用Linux上的c ++时遇到了问题。
我有一个基本的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)。
据我所知,这是一个单词对齐问题,但为什么内存对齐在不同的函数中不一致,为什么当使用new分配类的内存时,类成员的地址会变化。我使用的是Linux 2.6.27。 ,gcc版本4.1.1。 ,RHEL-4。
答案 0 :(得分:1)
为了排除非虚拟析构函数/复制/分配问题,请将以下内容添加到MsgBase
:
public:
virtual ~MsgBase();
private:
MsgBase(MsgBase const& other);
MsgBase& operator=(MsgBase const& other);
答案 1 :(得分:0)
我会尝试一步一步地提供所有必需的信息:
信息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