Нужна помощь в понимании перегрузки операторов в C ++ - PullRequest
1 голос
/ 02 сентября 2010

Я пытаюсь реализовать структуру, которая в основном представляет собой пользовательскую хеш-таблицу, содержащую либо ничего (NULL), либо указатель на двоичный объект дерева поиска.

Во всяком случае, у меня возникают проблемы с выяснением того, как сделать некоторые вещи, такие как установка хэш-таблицы, которая является массивом NULL, а также memcpy'ing BST-объектов из одной таблицы в другую.

BST *prevData;
BST *currData;

Насколько я понимаю, я думаю, что мне нужно перегрузить операторы = и ==, чтобы разрешить установку элементов массива в NULL, это правильно? Мне действительно непонятно, как реализовать все это, но, приведя примеры от Google, я получил:

BST& BST :: operator= (int null);
bool BST :: operator== (int null);

Перегрузка оператора == предназначена для проверки, равен ли индекс конкретного массива NULL. Я предполагаю, что мне нужен какой-то дополнительный код, а не только прототипы, и вот тут я отклеиваюсь.

Второй момент - это memcpy, что мне не разрешено делать компилятором.

memcpy(prevData[x], currData[x], sizeof(BST) * height);

Жалуется на

ошибка C2664: 'memcpy': невозможно преобразовать параметр 1 от 'BST' до 'void *' Нет пользовательский оператор преобразования доступно, что может выполнить это конвертация, или оператор не может быть называется

Если вам нужна дополнительная информация, я буду рад сообщить вам.

Есть какие-нибудь подсказки? Спасибо.

Ответы [ 2 ]

3 голосов
/ 02 сентября 2010

Как я понимаю, я думаю, что должен перегрузить операторы = и == в разрешить установку элементов массива в NULL, это правильно?

Нет, совсем нет. Вы описали массив BST * указателей, а не BST объектов. NULL уже является допустимым значением для указателя, вам не нужно изменять поведение C ++:

BST *array[LENGTH]; // LENGTH > 1
array[0] == NULL;
array[0] == new BST; // but watch for memory leaks!
array[1] == array[0];
array[0] == NULL; // now moved the array[0] pointer to array[1]

Каждый раз, когда у вас есть массив указателей, управление памятью становится сложным, и становится важным учитывать умные указатели, такие как shared_ptr.

РЕДАКТИРОВАТЬ: как обсуждалось в комментариях, лучшее решение состоит в том, чтобы иметь какое-то нулевое значение BST:

class BST {
    bool isNull_;
    BST() : isNull_(true) {}
    bool isNull() { return isNull_; }
    // rest of class definition...
};

Теперь у вас есть "пустое" значение BST, для которого bst.isNull_ - это истина. Значением по умолчанию является нулевое значение. Так что если вы создаете пустой вектор:

std::vector<BST> vec = std::vector<BST>(10);

это инициализирует до 10 нулевых BST. То же самое верно для оператора выделения массива new[].

Второй пункт - memcpy, который я не разрешается делать компилятор.

memcpy(prevData[x], currData[x], sizeof(BST) * height);

Не делай этого! Это неправильно по ряду причин, но в основном потому, что это устаревшая функция C, не подходящая для классов C ++; и потому что вы копируете один элемент, а не блок из них.

Чтобы скопировать один элемент, используйте operator=:

currData[x] = prevData[x];

Функция C ++ для копирования данных блока - std::copy. Одна из причин его использования заключается в том, что он может распознавать перегруженные operator= операторы присваивания, а memcpy - нет. Пример:

std::copy(prevData, prevData + LENGTH, currData);

(я полагаю, вы хотите скопировать из prevData в currData, как я сделал здесь, а не наоборот, как вы это сделали для memcpy ?)

0 голосов
/ 02 сентября 2010

Если бы это была не домашняя работа (это был твой тег?), Я бы порекомендовал одну unordered_map или карту.Вы понимаете, что это еще не сойдет вместе - лучше всего упростить это и заняться чем-то одним, а не откусывать больше, чем вы можете пережевать.Если вам нужна хэш-карта деревьев, я предлагаю вам начать строить ее из контейнеров C ++ STL, на которые вы можете положиться, а затем - если вы не должны использовать их для этой задачи - заменить их одно за другим, убедившись, чтовы используете высокоуровневое использование / тесты, работая так, как вы это делаете.Это означает:

typedef vector<map<T> > Container;
Container container;

Вы можете использовать container.resize (n), чтобы заполнить контейнер n пустыми картами, или увеличить контейнер с предыдущего размера до нового с дополнительными пустыми картами.

Действительно, начните с этого.Затем, если вам нужно в качестве упражнения, реализовать каждый вектор и карту независимо, и проверить их использование с помощью простых независимых тестовых примеров, прежде чем вставлять их обратно в вашу гибридную хэш-карту.

Может показаться, что янемного грубоват, поэтому давайте разберем немного вашего вопроса, чтобы увидеть некоторые заблуждения, о которых я говорил:

В любом случае, мне трудно понять, как сделать некоторые вещиНапример, установка хеш-таблицы, представляющей собой массив со значением NULL, а также создание BST-объектов memcpy из одной таблицы в другую.

Мой совет - не усложняйте и делайте то, что очевидно и чисто.Если вы должны использовать массив, а не вектор, то если он в стеке:

X* buckets[N];
for (int i = 0; i < sizeof buckets / sizeof buckets[0]; ++i)
    array[i] = NULL;

Если он в куче:

X** p_buckets = new X*[N];
for (int i = 0; i < N; ++i)
    array[i] = NULL;

Это медленнее, чем memset (),но это просто и понятно, и у вас появляется привычка думать о том, как перебирать контейнер, выполняя нужные операции.Для этого есть больше способов на C ++, но те же стили итерации труднее использовать для других произвольных задач, поэтому придерживайтесь этого, пока не освоитесь с ним полностью.

BST * prevData;BST * currData;

Насколько я понимаю, я думаю, что мне нужно перегрузить операторы = и ==, чтобы разрешить установку элементов массива в NULL, это правильно?Мне действительно неясно, как реализовать все это, но на примерах от Google я получил:

BST & BST :: operator = (int null);bool BST :: operator == (int null);Перегрузка оператора == предназначена для проверки, равен ли индекс конкретного массива NULL.Я предполагаю, что мне нужен какой-то дополнительный код, а не только прототипы, и вот тут я отклеиваюсь.

У вас есть два указателя на BST.Ваши хеш-таблицы представляют собой массив таких объектов, но только один из ваших комментариев предлагает вам представить их как указатели на две такие хеш-таблицы (вместо того, чтобы называть их временными переменными, записывающими ненулевые элементы во время итерации по хеш-таблице).Они должны быть BST **, так как они указывают на первый BST * в хэш-таблице.Но это очень опасный способ реализации ваших хеш-таблиц, так как клиент использует указатель на хеш-таблицу, а не указатель на некоторый класс, который обеспечивает безопасную реализацию концепции хеш-таблицы.С таким указателем все, что они могут сделать, - это индексировать конкретный BST, но нет связи ни с функциями, которые вы намереваетесь поддерживать хеш-таблицей, ни с переменными, которые отслеживают, сколько сегментов у него в настоящее время есть, сколько элементов в немсодержит и т. д. Вы должны поместить свои массивы в класс, который предоставляет все это;Есть много дизайнерских решений, но это должно выглядеть примерно так:

template <typename Key, typename Value>
class Hash
{
  public:
    Hash() : p_(NULL), size_(0), num_buckets_(0) { }

    // find/make entry for Key, giving read/write access to the current/a-default value
    Value& operator[](const Key&);        
    const Value& operator[](const Key&) const;

    // try to find an entry, throw an exception if not found...
    Value& at(const Key&);
    const Value& at(const Key&) const;

    // report whether a key is already in the hash table...
    bool has_key(const Key&) const;

    int size() const;

  private:
    BST* p_;
    int num_buckets_;
    int size_;
};

(опять же, я могу только рекомендовать сначала попробовать это с заменой p_ на этот вектор карт).

Второй момент - это memcpy, что мне не разрешено делать компилятором.

memcpy (prevData [x], currData [x], sizeof (BST) * height);

Жалуется на

ошибка C2664: 'memcpy': невозможно преобразовать параметр 1 из 'BST' в 'void *'Отсутствует пользовательский оператор преобразования, который мог бы выполнить это преобразование, или оператор не может быть вызван

Это очень странный запрос - скопировать все из одного сегмента в одной хэш-таблице в тот же блок в другом.хеш-таблица.Если, например, количество сегментов отличается или хеш-функция отличается, то вы, вероятно, испортите целевой контейнер.В любом случае, я предлагаю вам реализовать класс BST с семантикой значений (т. Е. Конструктор копирования и оператор =, который копирует существующее дерево).Тогда вы можете просто использовать:

prevData.buckets[x] = currData.buckets[x];

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...