Abhi
Abhi

Reputation: 1277

Derived Class Array not Formed

I am facing a problem while creating an array of derived class objects, and I can not find any explanation of this problem. The problem is the following:

I have an abstract base class RDMonitorBase and a derived class RDMonitorHashTable.

In another class RDMonitorPool I have the variable RDMonitorBase * m_rd_monitors.

In RDMonitorPool constructor I am creating an array of RDMonitorHashTable objects (using new) and assigning them to m_rd_monitors.

Immediately after the construction, only the even number indexed RDMonitorHashTable objects are properly formed. The objects with odd numbered index have garbage in the member variables. I have no idea why this is happening.

The code and the GDB output on a breakpoint immediately after the construction are given below:

Relevant parts of the RDMonitorBase and RDMonitorHashTable classes are as follows. I have a virtual Access() method in Base which is not implemented in the derived, and a pure virtual RecordDistance() method. Access() calls the RecordDistance() method. This should be okay I think, a similar structure worked when I created simple examples.

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();
}

Now in the RDMonitorPool class constructor, the following is basically executed:

RDMonitorBase * m_rd_monitors = new (std::nothrow) RDMonitorHashTable[4096];

After this line executes, when I try to print the objects in gdb, I get this:

(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}

So the even-indexed values have the proper values that are assigned in the constructor (for example 32 for m_maximum_distance). But the odd-index objexxts have garbage in m_maximum_distance and other members.

I will be extremely thankful if anybody can shed some light on why this is happening. Thanks!

Upvotes: 1

Views: 72

Answers (1)

brunocodutra
brunocodutra

Reputation: 2349

Your problem is addressed here: Base pointer to array of derived objects

The problem is that the array is of type RDMonitorBase, so when you try to access any of its positions, the compiler calculates the offset according to RDMonitorBase instead of RDMonitorHashTable, effectively dereferencing the memory at the wrong point and thus slicing up the actual object which is of a different type. From the point your program access any position of that array, its bahavior becomes undefined.

The most straightforward alternative would be to use an array of pointers to the base type and assign an object of the derived class dynamicaly constructed to each of them.

RDMonitorBase* m_rd_monitors[4096];
for(std::size_t i = 0; i < 4096; ++i)
    m_rd_monitors[i] = new (std::nothrow) RDMonitorHashTable;

Upvotes: 1

Related Questions