Linux 上 std::map 的内存对齐问题
我在 Linux 上使用 C++ 时遇到了问题。
我有一个消息基类,如下所示:
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。 ,海湾合作委员会版本4.1.1。 ,RHEL-4。
I have run into a problem while working with c++ over Linux.
I have a base Message class which looks like this:
class MsgBase
{
public:
MsgBase( unsigned int msgid );
map < unsigned int, MSGIEBase* > messageIE_Map; // map for IEs
unsigned int messageId; // 32 bit message id
};
class Der1 is derived from MsgBase and looks like:
class Der1 : public MsgBase
{
public:
Der1 ();
virtual ~Der1 ();
// IEs
MSGIE_UINT32 ueId;
MSGIE_String configFileName;
};
Here MSGIE_UINT32 and MSGIE_String are classes derived from MSGIEBase and therefore their address can be stored in the map defined in base class above.
When Der1 is constructed the address of ueId and configFileName is stored in the map.
Here if I print the size of map ( through gdb and in the program ) it comes to be 24.
[ _M_header = 16, _M_node_count = 4, _M_key_compare = 1, 3 byte padding I suppose ].
Till here everything is fine. Now the Der1 object pointer is put inside an event object and the event is post into a queue. The event class looks like:
class Event
{
public:
MsgBase* msgPtr;
};
A different thread removes the event from the queue, extracts the msgPtr and casts it into Der1 Pointer and this is where the problem starts.
Here if I print the size of the map in the program it is 21. That means the address of the next member in the MsgBase class i.e. messageId gets shifted by 3 bytes and so the value of messageId changes completely. (when seen through gdb, the address is still intact and so is the size of the map i.e. 24 ).
This is a word alignment issue to the best of my knowledge but why is the memory alignment not consistent in different functions and why does the address of a member of a class chage when the memory to the class has been allocated using new. I am using Linux 2.6.27. , gcc version 4.1.1. , RHEL-4.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为了排除非虚拟析构函数/复制/赋值问题,请将以下内容添加到
MsgBase
中:For ruling out non-virtual destructor/copy/assignment problems, please add the following to
MsgBase
:我将尝试逐步提供所有必需的信息:
信息1:相关代码。
信息2:确切的问题。
确切的问题是“messasgeId”在转换过程中发生了变化。最初它是 0xd,但从队列中弹出后它变成 0xd000000。因此,所有处理都会停止。在程序中打印时该参数的地址也从0x82bd7cc变为0x82bd7c9。然而,从 gdb 中看到,它仍然是 0x82bd7cc,并且值仍然是 0xd。
信息 3:编译器标志。
所有文件的编译器标志都是相同的,它们是:
-O0 -g3 -Wall -f消息长度=0
I will try to provide all the required information step by step:
Information 1 : The relevant code.
Information 2 : Exact problem.
The exact problem is that the 'messasgeId' is getting changed in transition. Initially it is 0xd but after popping from the queue it becomes 0xd000000. Because of this all the processing stops. The address of this parameter also changes from 0x82bd7cc to 0x82bd7c9 when printed in the program. However when seen from gdb it is still 0x82bd7cc and the value is still 0xd.
Information 3 : Compiler Flags.
Compiler Flags are same for all the files and they are:
-O0 -g3 -Wall -fmessage-length=0