2017-02-15 11 views
0

Я играю вокруг написания своего класса кучи. Мой шаблонный класс кучи требует, чтобы операторы '>' и '<' определялись по типу шаблона.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' – Arunmu

+2

Если вы беспокоитесь о слишком большом количестве копий, вы должны узнать о семантике перемещения, а не о прыгая прямо в 'std :: shared_ptr'. –

+0

@miles, я хотел бы узнать о семантике перемещения. Можете ли вы указать мне некоторые документы?Мне было интересно, есть ли какой-то специальный swap, который я мог бы использовать, чтобы обойти конструктор/деструктор. – nickdu

ответ

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; 
    } 
}; 

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

+0

спасибо. В моей реализации кучи используются как «>», так и «<», поэтому просто меньшее количество, вероятно, не будет достаточным. Кстати, я планировал разрешить поддержку типа сравнения, как это делают классы stl. – nickdu

+0

просто хочу убедиться, что я понимаю, что именно вы говорите. Вы упоминаете как оператор сравнения, так и тип компаратора. Является ли оператор только оператором() для типа сравнения? Кроме того, поскольку я использую оба параметра «<' and '>», мне интересно, нужно ли вместо этого вместо этого использовать оператор сравнения, а не предикат, так что мне может потребоваться только один дополнительный тип компаратора вместо двух. – nickdu

+0

@nickdu Использование 'operator <' или Comparator, как указано выше, в основном является выбором. Я предпочитаю Компаратор, поскольку он может быть передан как тип в параметрах шаблона, и это то же, что и стандартная библиотека. – Arunmu

 Смежные вопросы

  • Нет связанных вопросов^_^