Поиск векторов с помощью указателей пользовательского класса

#c #stl #vector

#c #stl #векторный

Вопрос:

Я пытаюсь понять операторы, которые вам нужно перегружать при работе с пользовательскими классами в STL (SCL).

Кто-нибудь, пожалуйста, может сказать мне, что я делаю не так?

 class myClass
{
public:
    int data;
    myClass()
    {
        data =0;
        cout<<"Default const "<<endl;
    }

    myClass(int x)
    {
        data = x;
        cout<<"Int constructor"<<endl;
    }

    myClass(const myClass amp;m)
    {
        cout<<"Copy constructor"<<endl;
    }

    bool operator == (const myClass amp;temp)
    {
        cout<<"Operator called amp;";
        return data == temp.data;
    }

    bool operator == (const myClass *temp)
    {
        cout<<"Operator called *";
        return data == temp->data;
    }
};

int main ()
{
    /*
    vector<int> myvector;
    myvector.push_back(10);
    myvector.push_back(20);
    myvector.push_back(30);

    cout << "myvector contains:";
    for_each (myvector.begin(), myvector.end(), meObj);
    */

    vector<myClass*> myVec;
    myClass temp;
    myVec.push_back(amp;temp);
    myClass temp2(19);
    myVec.push_back(amp;temp2);
    myClass temp3(19);

    vector<myClass*>::iterator it = find(myVec.begin(),myVec.end(),amp;temp2); //works
    if(it!=myVec.end())
    {
        cout<<"Value is "<<(*it)->data;
    }

    vector<myClass*>::iterator dit = find(myVec.begin(),myVec.end(),amp;temp3); //fails
    if(dit!=myVec.end())
    {
        cout<<"Value is "<<(*dit)->data;
    } 

    cout << endl;

    return 0;
}
  

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

Имеют ли смысл обе подписи?

 bool operator == (const myClass amp;temp); // seen in many places
bool operator == (const myClass *temp); // what if two pointer types of same object are being compared?
  

Приветствия!

Комментарии:

1. Вам действительно нужен вектор<T *> в вашем случае? Если да, пожалуйста, ознакомьтесь с контейнером указателей Boost ( boost.org/doc/libs/1_46_1/libs/ptr_container/doc /… ).

2. Ну, это всего лишь эксперимент с пониманием. Как я всегда думал, имея дело с динамическим распределением памяти, вы будете «сохранять» адрес элемента, а не элемент дважды в вашей программе. т.Е. один раз в новой и одной копии в контейнере.

Ответ №1:

Перегрузки оператора должны иметь хотя бы один пользовательский тип. Таким образом, вы не можете перегрузить, operator== например, два указателя.

Ваш myClass::operator==(const myClass *temp) действителен в том смысле, что он компилируется, но имеет очень мало семантического смысла и не рекомендуется (существует очень мало ситуаций, в которых вы хотели бы это сделать T x; T *y; ... (x == y) ).

Для вашей ситуации, когда у вас есть вектор указателей, вы можете рассмотреть std::find_if , который принимает предикат. Что-то вроде:

 class CompareByPointer
{
public:
    explicit CompareByPointer(const myClass amp;p) : p(p) {}
    bool operator() (const myClass amp;rhs) const { return p->data == rhs->data; }
private:
    const myClass amp;p;
};

...

find_if(myVec.begin(), myVec.end(), CompareByPointer(amp;temp2));
  

[В качестве дополнительного примечания, вам обычно следует определять функции-члены const везде, где это возможно. Таким образом, ваши перегрузки оператора должны быть const .]

Комментарии:

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

2. @Ricko: Вы можете, но при этом будут сравниваться сами указатели, а не то, на что они указывают.

3. @Ricko: и да, и нет. Как уже было сказано, перегруженные операторы могут применяться только к определяемым пользователем типам. Но вместо find вы можете использовать find_if , например, который вместо использования перегруженных операторов использует заданную пользователем функцию-предикат

4. Спасибо, ребята! Еще одна вещь, которую следует уточнить, когда вы говорите, что существует хотя бы один пользовательский тип, имеете ли вы в виду другой случай, как неявное преобразование встроенных типов в пользовательские типы с помощью неявного конструктора?

5. @Ricko: Компилятор попытается устранить перегрузку оператора максимум одним неявным преобразованием.

Ответ №2:

В примере кода вы не вставили amp;temp3 в myVec . Поэтому имеет смысл, чтобы второй std::find потерпел неудачу.

Комментарии:

1. да, это было сделано специально. Я хотел посмотреть, есть ли какие-либо операторы, которые я мог бы перегрузить, чтобы получить «правильный» логический результат.

Ответ №3:

Что вы подразумеваете под «работой» в этом случае? Как правило, когда вы сохраняете указатели, это происходит потому, что объекты действительно имеют идентификацию, и сравнение адреса — это правильная вещь. В противном случае вам, вероятно, следует сохранять значения (хотя есть исключения). В любом случае, вы всегда можете использовать find_if и любые критерии сравнения, которые вы хотите. В любом случае, я использую что угодно, кроме простейших типов, find_if чаще, чем find в любом случае; обычно вы ищете не равенство, а какой-то определенный тип соответствия. Здесь, например, вы, скорее всего, захотите что-то вроде:

 std::vector<MyClass>::iterator it = std::find_if( myVect.begin(), myVect.end(),
                                                  boost::bind(amp;MyClass::id, _1, 19) );
  

(Предположим, что data здесь есть какой-то идентификатор, и что вы предоставили функцию-член, myClass::id() чтобы прочитать его.)

Комментарии:

1. Под работой я подразумеваю, что сравнение в идеале должно возвращать true. Это нечто похожее на побитовое сравнение в отличие от фактического сравнения значений.

2. Я все еще не уверен, что понимаю. При каких условиях сравнение должно возвращать значение true? Как я уже сказал, вы решили разобраться с указателями. Наиболее вероятная причина заключается в том, что каждый объект имеет идентификатор, и объекты являются «равными» только в том случае, если они являются одним и тем же объектом. В противном случае используйте значения, а не указатели. (Это один из моих пунктов — другой заключается в том, что вы, вероятно, хотите find_if в любом случае, поскольку вы не хотите создавать полный объект только для проверки, равен ли идентификатор объекта 19.)