C++, использующий shared_ptr, но вызывающий реляционные операторы моего объекта?

Я играю вокруг, пишу свой собственный класс кучи. Мой шаблонный класс кучи требует, чтобы операторы '>' и '<' были определены в типе шаблона.

Казалось, что все работает нормально при использовании экземпляра примера класса, который я написал (а также отлично работал на int). Тем не менее, поскольку количество экземпляров настолько велико, что экземпляры классов перемещаются из разных узлов в куче, я решил посмотреть, что произошло, когда я создал кучу shared_ptr моего класса. В то время как я видел, как количество созданных экземпляров пошло вниз, куча не работала правильно, так как кажется, что вызывается умный указатель '>' и '<', который, я думаю, просто сравнивает ссылки умного указателя.

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

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

Куча моего образца, который работает нормально:

heap<foo> foo_heap(heap_type::max);
for (unsigned int i = 0; i < 10; ++i)
    {
    std::string s = "string ";
    s += ('0' + i);
    foo f(i, s);
    foo_heap.push(f);
    }
cout << "root: " << foo_heap.top() << endl;

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

heap<shared_ptr<foo>> foo_heap_smart(heap_type::max);
for (unsigned int i = 0; i < 10; ++i)
    {
    std::string s = "string ";
    s += ('0' + i);
    shared_ptr<foo> f(new foo(i, s));
    foo_heap_smart.push(f);
    }
cout << "root: " << *(foo_heap_smart.top()) << endl;

мой пример класса foo:

class foo
{
public:
    foo(int value, std::string s) : _value(value), _s(s)
    {
        std::cout << "foo::foo()" << std::endl;
    }

    foo(const foo& f) : _value(f._value), _s(f._s)
    {
        std::cout << "foo::foo(const foo& f)" << std::endl;
    }

    ~foo()
    {
        std::cout << "foo::~foo()" << std::endl;
    }

    virtual void operator=(const foo& f)
    {
        std::cout << "foo::operator=()" << std::endl;
        this->_value = f._value;
        this->_s = f._s;
    }

    virtual bool operator<(const foo& right)
    {
        return this->_value < right._value;
    }

    virtual bool operator>(const foo& right)
    {
        return this->_value > right._value;
    }

    void print(ostream& stm) const
    {
        stm << "value: " << this->_value << ", s: " << this->_s;
    }

private:
    int _value;
    std::string _s;
};

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

Спасибо ник

1 ответ

Решение

Предложенное решение состоит в том, чтобы предоставить собственную версию оператора сравнения, если стандартная версия не соответствует вашим потребностям. Лучший дизайн для вашего heap класс будет взять Comparator тип, который может по умолчанию std::less,

template <typename T, typename Comp = std::less<T>>
class heap {
...
};

А теперь предоставим вам собственную версию less специализируется на shared_ptr,

template <typename T>
struct less<shared_ptr<T>> {
    bool operator()(const shared_ptr<T>& a, const shared_ptr<T>& b) const {
      *a < *b;
    }
};

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

Другие вопросы по тегам