【发布时间】:2013-09-11 01:27:56
【问题描述】:
我在创建派生类对象数组时遇到了一个问题,我找不到这个问题的任何解释。问题如下:
我有一个抽象基类 RDMonitorBase 和一个派生类 RDMonitorHashTable。
在另一个类 RDMonitorPool 中,我有变量 RDMonitorBase * m_rd_monitors。
在 RDMonitorPool 构造函数中,我正在创建一个 RDMonitorHashTable 对象数组(使用新的) 并将它们分配给 m_rd_monitors。
在构造之后,只有偶数索引的 RDMonitorHashTable 对象被正确形成。具有奇数索引的对象在成员变量中有垃圾。我不知道为什么会这样。
代码和GDB在构建后立即断点处的输出如下:
RDMonitorBase 和 RDMonitorHashTable 类的相关部分如下。我在 Base 中有一个未在派生中实现的虚拟 Access() 方法,以及一个纯虚拟 RecordDistance() 方法。 Access() 调用 RecordDistance() 方法。我认为这应该没问题,当我创建简单示例时,类似的结构也起作用。
class RDMonitorBase {
public:
RDMonitorBase();
virtual void StartMonitoring(const physical_address_t& target_address, const int core_id);
virtual Index Access(const physical_address_t& address, const int core_id);
bool IsActive() { return m_active; }
static const Index TRACKING_NOT_COMPLETE = -1;
protected:
virtual void RecordDistance(const physical_address_t& address) = 0;
const Index m_maximum_distance;
bool m_active;
physical_address_t m_target_address;
Index m_distance;
int m_core_id;
};
class RDMonitorHashTable: public RDMonitorBase {
public:
RDMonitorHashTable();
virtual void StartMonitoring(const physical_address_t& target_address,
const int core_id);
protected:
virtual void RecordDistance(const physical_address_t& address);
std::tr1::unordered_set<physical_address_t> m_address_set;
};
RDMonitorBase::RDMonitorBase():
m_maximum_distance(32),
m_active(false),
m_target_address(0),
m_distance(0),
m_core_id(-1) { ; }
Index RDMonitorBase::Access(const physical_address_t& address,
const int core_id) {
// ... some code
RecordDistance(address);
//... some other code
return m_distance;
}
RDMonitorHashTable::RDMonitorHashTable()
:RDMonitorBase() { ; }
void RDMonitorHashTable::RecordDistance(const physical_address_t& address) {
m_address_set.insert(address);
m_distance = m_address_set.size();
}
现在在 RDMonitorPool 类的构造函数中,基本上执行了以下内容:
RDMonitorBase * m_rd_monitors = new (std::nothrow) RDMonitorHashTable[4096];
这一行执行后,当我尝试在 gdb 中打印对象时,我得到了这个:
(gdb) print *(m_rd_monitors + 0)
$2 = {_vptr.RDMonitorBase = 0x7ffd93cacc90, static TRACKING_NOT_COMPLETE = -1, m_maximum_distance = 32, m_active = false, m_target_address = 0, m_distance = 0, m_core_id = -1}
(gdb) print *(m_rd_monitors + 1)
$3 = {_vptr.RDMonitorBase = 0x1, static TRACKING_NOT_COMPLETE = -1, m_maximum_distance = 68540736, m_active = 11, m_target_address = 0, m_distance = 4611686019492741120, m_core_id = 11}
(gdb) print *(m_rd_monitors + 2)
$4 = {_vptr.RDMonitorBase = 0x7ffd93cacc90, static TRACKING_NOT_COMPLETE = -1, m_maximum_distance = 32, m_active = false, m_target_address = 0, m_distance = 0, m_core_id = -1}
(gdb) print *(m_rd_monitors + 3)
warning: can't find linker symbol for virtual table for `RDMonitorBase' value
$5 = warning: can't find linker symbol for virtual table for `RDMonitorBase' value
{_vptr.RDMonitorBase = 0x7ffda46b3e98, static TRACKING_NOT_COMPLETE = -1, m_maximum_distance = 68566480, m_active = 11, m_target_address = 0, m_distance = 4611686019492741120, m_core_id = 11}
因此,偶数索引值具有在构造函数中分配的正确值(例如,32 代表 m_maximum_distance)。但是奇数索引 objexxts 在 m_maximum_distance 和其他成员中有垃圾。
如果有人能解释为什么会发生这种情况,我将非常感激。谢谢!
【问题讨论】:
-
我没有时间仔细看这个,但我怀疑问题是
RDMonitorHashTable与RDMonitorBase的大小不同,因此*(m_rd_monitors + 1)没有'实际上并不指向第二个元素,而是指向第一个元素中间的某个位置(即new分配的对象是派生类型的正确大小,但由于指针指向基类型,它只添加 1) 时添加基本类型的大小。不知道为什么偶数索引值看起来合理 - 这可能只是内存布局的一些怪癖。 -
@BenS。这正是发生的事情,但即使偏移量在某种程度上完全相同并且它在内部起作用,依赖于此,不受支持并且行为未定义。
-
非常感谢!你们俩都找到了正确的原因。基类指针算法不应用于派生类对象。学习到教训了。生活又好起来了!
标签: c++ arrays inheritance