С ++ функтор для удаления указателей, кажется, работает - PullRequest
3 голосов
/ 17 августа 2011

В другом месте было предложено следующее для функтора удаления указателей в векторе

struct DeleteFromVector
{
    template <class T>
    void operator() ( T* ptr) const
    {
            delete ptr;
    }
};

вызывается с помощью

std::for_each(aVec.begin(), aVec.end(), DeleteFromVector());

Я написал нечто подобное (хотя изначально без умного перемещения шаблона внутри структуры):

    struct DeleteObj 
    {
        template<typename ObjType>
        inline void operator() (ObjType obj)
        { 
            delete obj; 
            obj = NULL; 
        };
    };

Проходя через него в отладчике, он, кажется, работает, то есть obj распознается как указатель, и ничего не вылетает.

Я немного сбит с толку относительно того, почему оба работают, и также хотел бы услышать мнения об использовании const и inline в них.

Спасибо, Роберт

Ответы [ 6 ]

3 голосов
/ 17 августа 2011

Первый должен быть предпочтительным, поскольку он будет компилироваться, только если тип векторного элемента является указателем. Второй компилируется, если тип векторного элемента может быть преобразован в не пустой указатель, что может привести к катастрофическим последствиям.

Функторы обычно объявляются как const, часто это не имеет значения, но это тоже ничего не стоит.

2 голосов
/ 17 августа 2011

Почему оба шаблона работают?

В первом шаблоне вы передаете Obj* методу шаблона, принимая T*, так что компилятор выводит, что TObj.

Во втором шаблоне вы передаете Obj* методу шаблона, принимая T, поэтому компилятор определяет, что T равно Obj*.


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

inline там избыточно, так как функции-члены определены внутри определения класса неявно inline.


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

Для функторов должно быть объявлено operator() const, если это возможно.Это потому, что нельзя передавать временные данные по неконстантной ссылке.Вызов std::for_each(...,..., Functor()); может не скомпилироваться, если только Functor не имеет operator(T)const.

Эта проблема запутана тем, что компиляторы Microsoft реализуют нестандартное расширение, позволяющее передавать временные значения не-const и включите это нестандартное поведение по умолчанию.

2 голосов
/ 17 августа 2011
  • Почему оба работают: если вы звоните operator()(U*), первый соответствует T = U, второй соответствует ObjType = U*.

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

  • встраивание - просто подсказка компилятора; Скорее всего, строительство будет встроено, несмотря ни на что. Определения членов внутри определений классов в любом случае неявно встроены.

2 голосов
/ 17 августа 2011

Это работает, потому что ObjType выводится как WhateverTypeYouHaveInYourVector *.При первом решении T определяется как WhateverTypeYouHaveInYourVector.Последнее лучше, потому что требует, чтобы аргумент был указателем, в то время как в вашем решении аргумент может быть любым, даже чем-то, что не может быть удалено.

Кстати, obj = NULL бесполезен, потому что вы беретепараметр по значению.Следовательно, указатель, который будет установлен в нуль, является копией, локальной для функции, а не той, которая содержится в векторе.Вместо этого вы можете взять ссылку на указатель:

struct Deleter
{
    template <typename T>
    void operator()( T * & ptr) const
    {
        delete ptr;
        ptr = 0;
    }
};
1 голос
/ 17 августа 2011

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

inline здесь избыточен, так как функция уже встроена.Также установка obj = NULL бесполезна, поскольку она устанавливает только вашу локальную копию указателя на 0, а не - как это, вероятно, предполагалось - запись в векторе.

0 голосов
/ 17 августа 2011

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

inline void operator() (ObjType* obj)

Это должно работать, как в верхнем примере.

inline - это оптимизация компилятора предложение , чтобы полностью скопировать функцию в каждое место, где она вызывается.

Ключевое слово const может использоваться по-разному, в зависимости от того, где вы его используете. В вашем случае (в первом примере) это означает, что класс или объект, для которого вызывается метод, не должны изменяться и могут использоваться в const контекстах.

...