1

我在创建派生类对象数组时遇到问题,我找不到这个问题的任何解释。问题如下:

我有一个抽象基类 RDMonitorBase 和一个派生类 RDMonitorHashTable。

在另一个类 RDMonitorPool 中,我有变量 RDMonitorBase * m_rd_monitors。

在 RDMonitorPool 构造函数中,我正在创建一个 RDMonitorHashTable 对象数组(使用 new)并将它们分配给 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 和其他成员中有垃圾。

如果有人能解释为什么会发生这种情况,我将非常感激。谢谢!

4

1 回答 1

1

您的问题在这里得到解决:Base pointer to array of derived objects

问题是数组是 type RDMonitorBase,所以当你尝试访问它的任何位置时,编译器会根据RDMonitorBase而不是计算偏移量RDMonitorHashTable,有效地在错误的点取消引用内存,从而将实际对象切片不同的类型。从您的程序访问该数组的任何位置的那一刻起,它的行为就变得未定义。

最直接的替代方法是使用指向基类型的指针数组,并将派生类的一个对象动态地构造给它们中的每一个。

RDMonitorBase* m_rd_monitors[4096];
for(std::size_t i = 0; i < 4096; ++i)
    m_rd_monitors[i] = new (std::nothrow) RDMonitorHashTable;
于 2013-09-11T01:55:16.533 回答