Присвойте значение, используя перегруженный оператор индекса - PullRequest
1 голос
/ 31 января 2012

Я пытаюсь создать пользовательский массив с индексом 1, используя оператор индекса.Получение значения работает нормально, но я понятия не имею, почему не работает присвоение с использованием оператора индекса.

class CEntry {
public:
  CKey key;
  CValue val;

  CEntry(const CKey& key, const CValue& val) {
    this->key = key;
    this->val = val;
  }

  CEntry& operator= (const CEntry& b) {
    *this = b;
    return *this;
  };
};

...

class EntriesArray {    
public:
    CEntry **entries;
    int length;

  EntriesArray(int length) {
    this->length = length;
    entries = new CEntry*[length];
    int i;
    for (i = 0; i < length + 1; i++) {
        entries[i] = NULL;
    }
  };

  CEntry& operator[] (const int index) {
      if (index < 1 || index > length) {
          throw ArrayOutOfBounds();
      }
      return *entries[index - 1];
  };

};

Создает массив таким образом

EntriesArray a(5);

Это работает

 a.entries[0] = new CEntry(CKey(1), CValue(1));
 cout << a[1].val.value << endl;

Это не работает

a[1] = new CEntry(CKey(1), CValue(1));

РЕДАКТИРОВАТЬ:

Использование

CEntry *operator=( CEntry *orig)

компилирует okey, но GDB останавливается на

No memory available to program now: unsafe to call malloc warning: Unable to restore previously selected frame

с обратным ходом

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00007fff5f3ffff8
0x00000001000013c8 in CEntry::operator= (this=0x0, orig=0x1001008d0) at /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp:20
20  /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp: No such file or directory.
in /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp

Ответы [ 6 ]

1 голос
/ 31 января 2012

Сначала ... Это:

CEntry& operator= (const CEntry& b) {
    *this = b;
    return *this;
};

Не должно работать (это должно привести к рекурсивному вызову operator=).

Во-вторых, выпытаясь присвоить CEntry * CEntry, это сработало бы, если бы у вас было CEntry *operator=( CEntry *orig), но я думаю, что это плохая практика кодирования.

0 голосов
/ 01 марта 2016

Этот вопрос может быть связан с этим .

Я пытался исправить твой код; Я считаю, что это то, что вы пытались сделать:

(протестировал этот код на g ++ 5.3.0)

#include <iostream>
#include <stdexcept>
#include <string>

// Some implementation for CKey and CValue:
typedef int CKey;
struct CValue {
  int value;
  CValue(int value=0) : value(value) {}
};

class CEntry {
public:
  CKey key;
  CValue val;

  CEntry(): key(0), val(0) {}
  CEntry(const CKey& key, const CValue& val): key(key), val(val) {}

  CEntry& operator= (const CEntry& b) {
    this->key = b.key;
    this->val = b.val;
    return *this;
  };
};

class EntriesArray {    
public:
    CEntry *entries;
    int length;

  EntriesArray(int length) {
    this->length = length;
    entries = new CEntry[length];
  };

  CEntry& operator[] (const int index) {
      if (index < 1 || index > length) {
          throw std::domain_error("out of bounds!");
      }
      return entries[index - 1];
  };

};

int main(int argc, char* argv[]) {
  using namespace std;

  EntriesArray a(5);

  // This works
  a.entries[0] = CEntry(CKey(1), CValue(1));
  cout << a[1].val.value << endl;

  // This doesn't work
  a[1] = CEntry(CKey(2), CValue(2));
  cout << a[1].val.value << endl;
}

Также вы можете использовать a[1] как a[1].val.value например ::

cout << a[1] << endl;

Для этого просто добавьте эту строку в cEntry:

operator int() { return val.value; }

Надеюсь, это поможет.

0 голосов
/ 31 января 2012

В дополнение к моему комментарию выше: Чтобы заставить его работать с написанием новых значений, вам, вероятно, нужно что-то вроде этого (Я не проверял дважды по одному или ptr против справочного материала)

CEntry& operator[] (const int index) {
  if (index < 1) {
      throw ArrayOutOfBounds();
  }
  // Add default elements between the current end of the list and the
  // non existent entry we just selected.
  //
  for(int i = length; i < index; i++)
  {
      // BUG is here.
      // We don't actually know how "entries" was allocated, so we can't
      // assume we can just add to it.
      // We'd need to try to resize entries before coming into this loop.
      // (anyone remember realloc()? ;-)
      entries[i] = new CEntry();
  }
  return *entries[index - 1];
};
0 голосов
/ 31 января 2012

Вы можете попробовать заменить

CEntry& operator[] (const int index) {
    if (index < 1 || index > length) {
        throw ArrayOutOfBounds();
    }
    return *entries[index - 1];
};

с

void Add(const int index, CEntry *pEntry) {
    if (index < 1 || index > length) {
        throw ArrayOutOfBounds();
    }
    entries[index - 1] = pEntry;
};

но так как вы сейчас храните ссылки на объекты, расположенные в куче (с новым), вам потребуется деструктор ~EntriesArray(), чтобы удалить их все.

0 голосов
/ 31 января 2012

Это

return *entries[index - 1];

разыменовывает нулевой указатель.

Вы хотите, чтобы сам указатель был перезаписан a[1] = new CEntry(CKey(1), CValue(1));, а не указателем на значение.

Попробуйте это:

class EntriesArray
{    
public:
  int length;
  CEntry **entries;

  EntriesArray( int length ) : length(length), entries(new CEntry*[length]())
  {
  }

  // defaulted special member functions are inappropriate for this class
  EntriesArray( const EntriesArray& );          // need custom copy-constructor
 ~EntriesArray();                               // need custom destructor
  EntriesArray& operator=(const EntriesArray&); // need custom assignment-operator

  CEntry*& operator[] (const int index) {
      if (index < 1 || index > length) {
          throw ArrayOutOfBounds();
      }
      return entries[index - 1];
  }
};
0 голосов
/ 31 января 2012

Поскольку EntriesArray::operator[] возвращает CEntry &, а new CEntry возвращает CEntry *.

Возможно, вы хотите a[1] = CEntry(CKey(1), CValue(1))? (нет new.)


Кстати, ваше текущее определение CEntry::operator= приведет к переполнению стека.

...