Вызов for_each не будет работать с вектором указателей

Я использую вектор указателей, чтобы освободить ряд объектов узла в куче. В векторе есть все адреса узловых объектов, и есть функция delete_nodes, которая используется с циклом for_each для удаления всех узлов в векторе. По какой-то причине я получаю следующую ошибку в eclipse cdt с циклом for_each, подчеркнутым красным:

error: no matching function for call to 'for_each(__gnu_cxx::__normal_iterator<Node**, std::vector<Node*, std::allocator<Node*> > >, __gnu_cxx::__normal_iterator<Node**, std::vector<Node*, std::allocator<Node*> > >, <unresolved overloaded function type>)'

Код предназначен для кодирования Хаффмана, а цикл for_each находится в самом конце. Вектор nodes_delete создается прямо перед циклом while.

void Huff::delete_nodes(Node*n){//this is used to delete all the nodes in the binary tree at the end of Huff::compress()
    delete n;
}
vector<Code>* Huff::compress(){
    //-------GETTING WEIGHTS/FREQUENCIES------
    vector<Node *>* nodes = new vector<Node*>; // Vector of nodes for later use
    map<char, int>* freq = new map<char, int>; //  Map to find weight of nodes
    for(unsigned int i = 0; i < content.length(); i++)
        (*freq)[content[i]]++; 
    CopyTo copyto(nodes); //sets vector<Node*> to copy to 
    for_each(freq->begin(), freq->end(), copyto); // Copies 
    delete freq;
    vector<Node *>::iterator beg = nodes->begin();

    //-------SETTING UP TO BUILD TREE------
    if(nodes->size() % 2 == 1){ //makes sure there are an even number of nodes
        Node* fill = new Node;
        fill->set_node(0, '*', NULL, NULL);
        nodes->push_back(fill);
    }
    huff_sort(nodes); // sort nodes by weight
    vector<Node*> nodes_delete(*nodes); //this is used to delete all the nodes in the binary tree at the end
    //-------BUILDING TREE------
    while(nodes->size() != 1){ //Sorts nodes by weight and then removes two of them and replaces them with one
        int w= (**beg).weight + (**(beg+1)).weight;
        Node* p = new Node;
        p->set_node(w, '*', *nodes->begin(), *(nodes->begin()+1)); //making it the parent node of the two lowest nodes
        nodes->erase(nodes->begin(), nodes->begin()+2);
        unsigned int i = 0;
        while(w > (*nodes)[i]->weight && i <= nodes->size()){ //finds where to insert the parent node based on weight
            i++;
        }
        if(i > nodes->size()) //if it needs to be inserted at the end
            nodes->push_back(p);
        else
            nodes->insert(nodes->begin()+i, p);
    }
    //-------TRAVERSING TREE------
    Node* root = (*nodes)[0];
    delete nodes;
    vector<Code>* codes = new vector<Code>;
    traverse(root, codes , "");
    delete root;
    for_each(nodes_delete.begin(), nodes_delete.end(), delete_nodes);
    return codes;
}

person sinθ    schedule 25.07.2012    source источник
comment
Есть ли более одного (перегруженного) определения для функции delete_nodes? В приведенном выше коде я вижу только один, но вы проверяли, есть ли еще один, возможно, в одном из заголовочных файлов?   -  person jogojapan    schedule 25.07.2012
comment
@jogojapan Насколько мне известно, других узлов удаления нет. Кроме того, если я изменю имя delete_nodes на любое другое, ошибка сохранится.   -  person sinθ    schedule 25.07.2012
comment
Кстати, я предположил, что функция delete_nodes определена как статическая функция-член. Это действительно правильно? Если нет, Matteo Italia ниже прав (хотя я бы нашел сообщение об ошибке компилятора в этом случае довольно вводящим в заблуждение).   -  person jogojapan    schedule 25.07.2012
comment
@jogojapan Нет, я проверил, и это не было определено как статическая функция-член. Я изменил его, и теперь он работает.   -  person sinθ    schedule 25.07.2012
comment
указатели на векторы и векторы указателей... вы настроены на утечку памяти, не так ли? :) Семантика перемещения/RVO и умные указатели - ваши друзья (если вам даже нужны указатели в вашем векторе, которых у вас, вероятно, нет). Вы также можете просто передать vector<T>& для заполнения функцией.   -  person Ed S.    schedule 25.07.2012
comment
В коде слишком много вызовов new и delete. Возможно, вы захотите переосмыслить то, что вам нужно (может быть полезна книга по C++)   -  person David Rodríguez - dribeas    schedule 25.07.2012
comment
@DavidRodríguez-dribeas Извините, ваш комментарий немного сбивает с толку. Что вы подразумеваете во втором предложении под словом «нужно». Кроме того, я могу создать какой-то недостаток дизайна, но что бы это ни было, это не описано в основных книгах по С++, которые я читал (насколько я знаю). Итак, не могли бы вы уточнить, какая книга по С++?   -  person sinθ    schedule 25.07.2012
comment
@MikeG: В ваших книгах говорилось о динамическом размещении стандартных контейнеров? Если это так, подумайте о приобретении разных книг. В некоторых случаях вам нужно динамически размещать объекты, но в большинстве случаев вы должны быть в состоянии не писать new, и, конечно же, вы можете обойтись без delete (используя смарт-контейнеры для тех немногих случаев, когда вы действительно нужно динамически выделять). Какой у тебя Node тип? Вам нужно хранить указатели на него в std::vector? Или, может быть, достаточно просто значений? Чем меньше указателей вы используете, тем проще код.   -  person David Rodríguez - dribeas    schedule 25.07.2012
comment
@DavidRodríguez-dribeas Это была довольно простая книга, поэтому в ней даже не упоминалось об использовании указателей с контейнерами. Указатель на узлы, насколько я знаю, был неизбежен из-за того, как я строил двоичное дерево (что и делает программа). Спасибо, но я посмотрю на то, что вы сказали.   -  person sinθ    schedule 25.07.2012
comment
@MikeG: довольно простая книга, поэтому в ней даже не упоминается использование указателей с контейнерами -- я все еще жду, когда найду книгу, которая проинструктирует вас о динамическом размещении контейнеров. Это не показатель базового.   -  person David Rodríguez - dribeas    schedule 25.07.2012


Ответы (2)


Похоже, ваша delete_nodes является нестатической функцией-членом. Если это так, вы не можете просто использовать delete_nodes в качестве аргумента для std::for_each. std::for_each требуется функтор. Ваш delete_nodes не функтор.

Во-первых, для получения указателя на нестатическую функцию-член всегда требуются оператор & и полное имя. Простое имя нестатической функции-члена (просто delete_nodes) не является допустимым выражением в C++. Вы должны сделать &Huff::delete_nodes.

Во-вторых, опять же, указатель на функцию-член (в отличие от указателя на «обычную» функцию) не является функтором. Чтобы превратить его в функтор, вы можете использовать функцию std::mem_fun. Это даст вам двоичный функтор, поскольку std::mem_fun превратит неявный параметр this в явный. Чтобы превратить его в унарный функтор, требуемый std::for_each, вы должны привязать первый аргумент к определенному значению указателя объекта (вероятно, this?).

Конечный результат вышеуказанных шагов будет выглядеть как

bind1st(mem_fun(&Huff::delete_nodes), this)

Это унарный функтор, который вызывает delete_nodes для объекта this.

Итак, вызов for_each в вашем примере должен выглядеть следующим образом

for_each(nodes_delete.begin(), nodes_delete.end(),
  bind1st(mem_fun(&Huff::delete_nodes), this));

Однако похоже, что в вашей реализации delete_nodes можно превратить в статическую функцию-член. Статическая функция-член — это «обычная» функция, что означает, что она является функтором и может использоваться напрямую. т.е. если вы сделаете delete_nodes статическим, ваш код должен работать как есть.

Решите, по какому пути вы хотите пойти, и внесите необходимые изменения.

person AnT    schedule 25.07.2012

Вы пытаетесь передать в качестве функтора неограниченную функцию-член. Вы должны привязать его к текущему объекту, используя, например. std::mem_fn и bind.

person Matteo Italia    schedule 25.07.2012