Сравнение vector<shared_ptr>
От: Alexander Pazdnikov  
Дата: 29.12.11 10:45
Оценка:
Здравствуйте, Коллеги.

Помогите, пожалуйста, перегрузить оператор сравнения для std::vector<boost::shared_ptr> чтобы сравнивались не указатели, а объекты по этим указателям.

#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <iostream>

using namespace std;
using namespace boost;

int main()
{
    vector<shared_ptr<int> > v1, v2;

    v1.push_back(make_shared<int>(1));
    v2.push_back(make_shared<int>(1));

    bool equal = v1 == v2; // здесь хочу получить true вместо false

    cout << equal << endl;
    
    cout << "v1[0] = " << v1[0] << " -> " << *v1[0] << endl;
    cout << "v2[0] = " << v2[0] << " -> " << *v2[0] << endl;

    vector<int> v3, v4;

    v3.push_back(1);
    v4.push_back(1);
    
    equal = v3 == v4;

    cout << equal << endl;
    
    cout << "v3[0] = " << v3[0] << endl;
    cout << "v4[0] = " << v4[0] << endl;

    return 0;
}
vector shared_ptr equal сранение
Re: Сравнение vector<shared_ptr>
От: Сыроежка  
Дата: 29.12.11 11:11
Оценка:
Здравствуйте, Alexander Pazdnikov, Вы писали:

AP> Здравствуйте, Коллеги.


AP>Помогите, пожалуйста, перегрузить оператор сравнения для std::vector<boost::shared_ptr> чтобы сравнивались не указатели, а объекты по этим указателям.


AP>
AP>#include <vector>
AP>#include <boost/shared_ptr.hpp>
AP>#include <boost/make_shared.hpp>
AP>#include <iostream>

AP>using namespace std;
AP>using namespace boost;

AP>int main()
AP>{
AP>    vector<shared_ptr<int> > v1, v2;

AP>    v1.push_back(make_shared<int>(1));
AP>    v2.push_back(make_shared<int>(1));

AP>    bool equal = v1 == v2; // здесь хочу получить true вместо false

AP>    cout << equal << endl;
    
AP>    cout << "v1[0] = " << v1[0] << " -> " << *v1[0] << endl;
AP>    cout << "v2[0] = " << v2[0] << " -> " << *v2[0] << endl;

AP>    vector<int> v3, v4;

AP>    v3.push_back(1);
AP>    v4.push_back(1);
    
AP>    equal = v3 == v4;

AP>    cout << equal << endl;
    
AP>    cout << "v3[0] = " << v3[0] << endl;
AP>    cout << "v4[0] = " << v4[0] << endl;

AP>    return 0;
AP>}
AP>


Вы можете воспользоваться стандартным алгоритмом std::lexicographical_compare с предикатом.
Меня можно встретить на www.cpp.forum24.ru
Re[2]: Сравнение vector<shared_ptr>
От: Alexey F  
Дата: 29.12.11 11:29
Оценка: +2
Здравствуйте, Сыроежка, Вы писали:

AP>>
...
AP>>    bool equal = v1 == v2; // здесь хочу получить true вместо false
...
AP>>

С>Вы можете воспользоваться стандартным алгоритмом std::lexicographical_compare с предикатом.
Эмм...

std::lexicographical_compare

Lexicographical less-than comparison
Returns true if range [first1,last1) compares lexicographically less than the range [first2,last2).

Если и говорить про алгоритмы, то нужен std::equal со своим предикатом, но только с проверкой длины векторов:
bool equal = v1.size() == v2.size() && std::equal( v1.begin(), v1.end(), v2.begin(), predicate );

Не думаю, что топик-стартеру понравится.
Re[3]: Сравнение vector<shared_ptr>
От: Сыроежка  
Дата: 29.12.11 11:38
Оценка: -1
Здравствуйте, Alexey F, Вы писали:

AF>Здравствуйте, Сыроежка, Вы писали:


AP>>>
AF>...
AP>>>    bool equal = v1 == v2; // здесь хочу получить true вместо false
AF>...
AP>>>

С>>Вы можете воспользоваться стандартным алгоритмом std::lexicographical_compare с предикатом.
AF>Эмм...
AF>

AF>std::lexicographical_compare

AF>Lexicographical less-than comparison
AF>Returns true if range [first1,last1) compares lexicographically less than the range [first2,last2).

AF>Если и говорить про алгоритмы, то нужен std::equal со своим предикатом, но только с проверкой длины векторов:
AF>
AF>bool equal = v1.size() == v2.size() && std::equal( v1.begin(), v1.end(), v2.begin(), predicate );
AF>

AF>Не думаю, что топик-стартеру понравится.

Совершенно не понял, почему вы вместо std::lexicographical_compare предлагаете использлвать std::equal, когда последний не сравнивает размеры диапазонов?! Или это вы так стараетесь себе жизнь усложнить?! std::lexicographical_compare вполне подходит для выяснения равны между собой две последовательности или нет.
Меня можно встретить на www.cpp.forum24.ru
Re[4]: Сравнение vector<shared_ptr>
От: Alexey F  
Дата: 29.12.11 11:48
Оценка:
Здравствуйте, Сыроежка, Вы писали:

С>Совершенно не понял, почему вы вместо std::lexicographical_compare предлагаете использлвать std::equal, когда последний не сравнивает размеры диапазонов?! Или это вы так стараетесь себе жизнь усложнить?! std::lexicographical_compare вполне подходит для выяснения равны между собой две последовательности или нет.

Из-за его стандартной семантики — процитированное:

Returns true if range [first1,last1) compares lexicographically less than the range [first2,last2).

Лично я бы удивился, если бы, к примеру, operator< вдруг стал использоваться для проверки на равенство, а std::max_element с пользовательским предикатом стал бы возвращать минимальный элемент
Re[3]: Сравнение vector<shared_ptr>
От: uzhas Ниоткуда  
Дата: 29.12.11 11:56
Оценка:
Здравствуйте, Alexey F, Вы писали:

AF>Не думаю, что топик-стартеру понравится.

ваш вариант в бою: http://ideone.com/EWZDO
Re: Сравнение vector<shared_ptr>
От: night beast СССР  
Дата: 29.12.11 12:00
Оценка: +2
Здравствуйте, Alexander Pazdnikov, Вы писали:

AP> Здравствуйте, Коллеги.


AP>Помогите, пожалуйста, перегрузить оператор сравнения для std::vector<boost::shared_ptr> чтобы сравнивались не указатели, а объекты по этим указателям.


своя обертка над shared_ptr не подходит?
Re[4]: Сравнение vector<shared_ptr>
От: uzhas Ниоткуда  
Дата: 29.12.11 12:02
Оценка: 3 (2)
Здравствуйте, uzhas, Вы писали:

U>ваш вариант в бою:

что-то в компараторе накосячил
дубль2: http://ideone.com/SGpw7
Re[5]: Сравнение vector<shared_ptr>
От: Сыроежка  
Дата: 29.12.11 12:02
Оценка: -1
Здравствуйте, Alexey F, Вы писали:

AF>Здравствуйте, Сыроежка, Вы писали:


С>>Совершенно не понял, почему вы вместо std::lexicographical_compare предлагаете использлвать std::equal, когда последний не сравнивает размеры диапазонов?! Или это вы так стараетесь себе жизнь усложнить?! std::lexicographical_compare вполне подходит для выяснения равны между собой две последовательности или нет.

AF>Из-за его стандартной семантики — процитированное:
AF>

AF>Returns true if range [first1,last1) compares lexicographically less than the range [first2,last2).

AF>Лично я бы удивился, если бы, к примеру, operator< вдруг стал использоваться для проверки на равенство, а std::max_element с пользовательским предикатом стал бы возвращать минимальный элемент

А причем здесь этот оператор? Вы же используете алгоритм с предикатом. Можно исхитриться и придумать предикат, который будет давать нужный результат. Например, предикат, который будет возращать значение оператора != при каждом нечетном вызове предиката.
Меня можно встретить на www.cpp.forum24.ru
Re[4]: Сравнение vector<shared_ptr>
От: Alexey F  
Дата: 29.12.11 12:06
Оценка:
Здравствуйте, Сыроежка, Вы писали:

Да более того (сразу не посмотрел). lexicographical_compare возвратит true на первых же равных элементах, т.е. предикаты вида { return a == b } не напишешь:
for ( ; first1 != last1 && first2 != last2 ; ++first1, ++first2) {
    if (cmp(*first1, *first2)) return true;
    if (cmp(*first2, *first1)) return false;
}
return first1 == last1 && first2 != last2;
Re[6]: Сравнение vector<shared_ptr>
От: Alexey F  
Дата: 29.12.11 12:19
Оценка:
Здравствуйте, Сыроежка, Вы писали:

С>Вы же используете алгоритм с предикатом. Можно исхитриться и придумать предикат, который будет давать нужный результат. Например, предикат, который будет возращать значение оператора != при каждом нечетном вызове предиката.

Для lexicographical_compare придётся писать предикат сложнее a == b:
здесь
Автор: Alexey F
Дата: 29.12.11

(код взят из стандарта, только < заменён на cmp) и даже не a != b с отрицанием результата — это ещё больше (помимо вводящего в заблуждение имени) затуманит цель кода для того, кто будет потом в нём разбираться.
Re[7]: Сравнение vector<shared_ptr>
От: Сыроежка  
Дата: 29.12.11 12:31
Оценка: :)
Здравствуйте, Alexey F, Вы писали:

AF>Здравствуйте, Сыроежка, Вы писали:


С>>Вы же используете алгоритм с предикатом. Можно исхитриться и придумать предикат, который будет давать нужный результат. Например, предикат, который будет возращать значение оператора != при каждом нечетном вызове предиката.

AF>Для lexicographical_compare придётся писать предикат сложнее a == b:
AF>здесь
Автор: Alexey F
Дата: 29.12.11

AF>(код взят из стандарта, только < заменён на cmp) и даже не a != b с отрицанием результата — это ещё больше (помимо вводящего в заблуждение имени) затуманит цель кода для того, кто будет потом в нём разбираться.

На самом деле предикат простой и не затуманит. Другое дело, что внутри алгоритма этот предикат вызывается дважды, что, как говорится, не комильфо. А так написать предикат очень просто. Достаточно завести внутри класса логической переменную, при каждом вызове предиката которая будет менть значение на прлтивоположное. При первом вызове предиката сотреть, если эта переменная равна false, то возвращать ее. При втором вызове возвращать условие a != b

То есть оператор функции будет состоять из одной строчки

return ( ( first = !first ) && ( a != b ) );

При этом начальное значение first должно быть равно true
Меня можно встретить на www.cpp.forum24.ru
Re[8]: Сравнение vector<shared_ptr>
От: uzhas Ниоткуда  
Дата: 29.12.11 12:35
Оценка:
Здравствуйте, Сыроежка, Вы писали:

С>Достаточно завести внутри класса логической переменную, при каждом вызове предиката которая будет менть значение на прлтивоположное. При первом вызове предиката сотреть, если эта переменная равна false, то возвращать ее. При втором вызове возвращать условие a != b

бросай курить, вставай на лыжи!
Re[4]: Сравнение vector<shared_ptr>
От: Centaur Россия  
Дата: 29.12.11 12:42
Оценка:
Здравствуйте, Сыроежка, Вы писали:

С>std::lexicographical_compare вполне подходит для выяснения равны между собой две последовательности или нет.


Не подходит. Лексикографическое сравнение в лучшем случае даст эквивалентность (!(a<b) && !(b<a)), а не равенство (a==b). И нет, эти отношения не обязаны быть согласованы для конкретного типа—аргумента шаблона.

Поэтому таки std::equal, с предварительным сравнением размеров и с кастомным предикатом вида [](x,y) { return *x == *y; }.
Re[5]: Сравнение vector<shared_ptr>
От: Сыроежка  
Дата: 29.12.11 12:49
Оценка: -1
Здравствуйте, Alexey F, Вы писали:

AF>Здравствуйте, Сыроежка, Вы писали:


AF>Да более того (сразу не посмотрел). lexicographical_compare возвратит true на первых же равных элементах, т.е. предикаты вида { return a == b } не напишешь:

AF>
AF>for ( ; first1 != last1 && first2 != last2 ; ++first1, ++first2) {
AF>    if (cmp(*first1, *first2)) return true;
AF>    if (cmp(*first2, *first1)) return false;
AF>}
AF>return first1 == last1 && first2 != last2;
AF>



Я вам уже ответил в другом месте. Но повторю здесь свой ответ.

На самом деле предикат простой и не затуманит. Другое дело, что внутри алгоритма этот предикат вызывается дважды, что, как говорится, не комильфо. А так написать предикат очень просто. Достаточно завести внутри класса логической переменную, при каждом вызове предиката которая будет менть значение на прлтивоположное. При первом вызове предиката смотреть, если эта переменная равна false, то возвращать ее. При втором вызове возвращать условие a != b

То есть оператор функции будет состоять из одной строчки

return ( ( first = !first ) && ( a != b ) );

При этом начальное значение first должно быть равно true
Меня можно встретить на www.cpp.forum24.ru
Re[6]: Сравнение vector<shared_ptr>
От: Centaur Россия  
Дата: 29.12.11 13:35
Оценка:
Здравствуйте, Сыроежка, Вы писали:

С>Можно исхитриться и придумать предикат, который будет давать нужный результат. Например, предикат, который будет возращать значение оператора != при каждом нечетном вызове предиката.


Так нельзя делать, потому что предикат должен индуцировать отношение строгого слабого порядка.
Re[5]: Сравнение vector<shared_ptr>
От: Кодт Россия  
Дата: 29.12.11 13:50
Оценка:
Здравствуйте, Centaur, Вы писали:

C>Не подходит. Лексикографическое сравнение в лучшем случае даст эквивалентность (!(a<b) && !(b<a)), а не равенство (a==b). И нет, эти отношения не обязаны быть согласованы для конкретного типа—аргумента шаблона.


Ну, если над типом введены два НЕЗАВИСИМЫХ отношения — равенство (==) и порядок (<), тогда конечно.
Но обычно, всё-таки, если определено <, то все остальные отношения следуют ему: a>b = b<a, a<=b = !(b>a), a!=b = (a<b)||(b<a) и т.д.

Другое дело, что над типом может отсутствовать отношение порядка, а только равенство.
Вот тогда без std::equal или его рукодельных аналогов деваться некуда
template<class I, class J>
bool equal_ranges(I i, I ie, J j, J je)
{
  while(i!=ie && j!=je && *i==*j) { ++i; ++j; }
  return i==ie && j==je;
}

template<class I, class J, class E>
bool equal_ranges(I i, I ie, J j, J je, E eq)
{
  while(i!=ie && j!=je && eq(*i,*j)) { ++i; ++j; }
  return i==ie && j==je;
}
Перекуём баги на фичи!
Re[6]: Сравнение vector<shared_ptr>
От: Кодт Россия  
Дата: 29.12.11 13:55
Оценка:
Здравствуйте, Сыроежка, Вы писали:

С>А причем здесь этот оператор? Вы же используете алгоритм с предикатом. Можно исхитриться и придумать предикат, который будет давать нужный результат. Например, предикат, который будет возращать значение оператора != при каждом нечетном вызове предиката.


Stateful функция плоха тем, что вызывающая сторона должна специфицировать порядок её вызова.

Вот, например, для for_each этот порядок определён, а для всяких операций сравнения — нет.
Этим пользуются дебажные версии библиотек, проверяя, соответствует ли аргумент-предикат требуемой аксиоматике, а если данные должны быть упорядочены — то заодно, упорядочены ли они на самом деле?

Так что этот фокус с чётностью прокатит только для одной конкретной версии STL, притом, что работать он будет в режиме undefined behavior (которое в частном случае является искомым и желанным поведением...)
Перекуём баги на фичи!
Re[6]: Сравнение vector<shared_ptr>
От: Centaur Россия  
Дата: 29.12.11 16:19
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Ну, если над типом введены два НЕЗАВИСИМЫХ отношения — равенство (==) и порядок (<), тогда конечно.

К>Но обычно, всё-таки, если определено <, то все остальные отношения следуют ему: a>b = b<a, a<=b = !(b>a), a!=b = (a<b)||(b<a) и т.д.

Не уверен, что это справедливо хотя бы даже для юникодной строки. Ну и вообще любые типы с существенно частичным порядком.
Re[7]: Сравнение vector<shared_ptr>
От: Кодт Россия  
Дата: 29.12.11 17:05
Оценка:
Здравствуйте, Centaur, Вы писали:

C>Не уверен, что это справедливо хотя бы даже для юникодной строки. Ну и вообще любые типы с существенно частичным порядком.


Ну если юникодную строку нарочно сравнивать не через strcmp (wcscmp), а через strcoll, — то конечно.
Это как раз ситуация, когда отношения равенства и порядка будут введены произвольно и без оглядки друг на друга. ССЗБ.

Часто (не знаю, как в жизни, а на форумах точно) люди вводят оператор < над своим типом от балды, просто потому, что это требование какого-нибудь контейнера (std::map) или алгоритма (std::sort). Естественно, что в лучшем случае они заботятся об аксиоматике порядка (и то не всегда, а иногда — да вот прямо здесь! — заботятся о том, чтобы её безболезненно сломать). А об согласовании с другими операторами даже не вспоминают.

Кстати, в бусте есть заготовка, порождающая наборы всяких разных операторов
http://www.boost.org/doc/libs/1_48_0/libs/utility/operators.htm
Перекуём баги на фичи!
Re: Сравнение vector<shared_ptr>
От: jazzer Россия Skype: enerjazzer
Дата: 30.12.11 03:35
Оценка:
Здравствуйте, Alexander Pazdnikov, Вы писали:

AP> Здравствуйте, Коллеги.


AP>Помогите, пожалуйста, перегрузить оператор сравнения для std::vector<boost::shared_ptr> чтобы сравнивались не указатели, а объекты по этим указателям.


Не надо так делать — проблем потом не оберешься.
Сделай отдельную функцию, которая будет этим заниматься.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Сравнение vector<shared_ptr>
От: Alexander Pazdnikov  
Дата: 30.12.11 04:28
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Не надо так делать — проблем потом не оберешься.

J>Сделай отдельную функцию, которая будет этим заниматься.

Почему не надо так делать?
Какие проблемы могу огрести?

Сейчас использую в тестах,

BOOST_CHECK_EQUAL(orig_container, computed_container);

В случае перегрузки operator== пользуюсь ими стандартными способами.
Re[3]: Сравнение vector<shared_ptr>
От: jazzer Россия Skype: enerjazzer
Дата: 30.12.11 05:19
Оценка: 2 (1) +3
Здравствуйте, Alexander Pazdnikov, Вы писали:

J>>Не надо так делать — проблем потом не оберешься.

AP>Почему не надо так делать?
AP>Какие проблемы могу огрести?

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

AP>Сейчас использую в тестах,

AP>BOOST_CHECK_EQUAL(orig_container, computed_container);
AP>В случае перегрузки operator== пользуюсь ими стандартными способами.

Нарушение ODR не пугает?

Чтобы всех этих проблем избежать, лучше завернуть этот вектор в класс, у которого ты сделаешь все необходимые методы сравнения и чего угодно еще.
Этот класс будет новой сущностью, НЕ вектором, а стало быть, все рассуждения, применимые к вектору, к нему самому применимы уже не будут.
С другой стороны, вектор, который сидит внутри этого класса, останется нормальным вектором с обычной семантикой, и любой обобщенный код, работающий с векторами, будет правильно с ним работать.

Заодно (по моему собственному опыту), несмотря на то, что это выглядит поначалу просто как примитивная тонкая обертка над вектором, как только ты создашь этот класс, окажется, что в него еще много чего связанного можно запихнуть, а результирующий код станет намного чище, и это именно потому, что твоя основная сущность — это все-таки не вектор, раз у него понадобилось так неочевидно менять семантику.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: Сравнение vector<shared_ptr>
От: Alexander Pazdnikov  
Дата: 30.12.11 05:50
Оценка:
Здравствуйте, jazzer, Вы писали:

Большое Спасибо, очень развёрнуто. Так и сделаю.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.