Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

[C++]Сложный объект в качестве ключа std::map

10K
27 января 2012 года
Cybernetic
106 / / 22.07.2009
Есть несложный класс, он описан в библиотеке MyLib.lib:
Код:
#pragma once

class MyClass
{
public:
    unsigned int WordId;
    ...
    bool operator<(const WordId object2)
    {
        return WordId < object2.WordId;
    }
    ....
}


После подключения данной либы в другой проект, собираюсь использовать ассоциативный список:
 
Код:
#include "MyClass.h"
#include <map>

void OtherClass::OtherFunc()
{
    MyClass myClass = GetMyObject();
    std::map<MyClass, int>::iterator iter = container.find(myClass);
}


И компилятор сражу же выдает ошибку:
Цитата:
error C2678: binary '<' : no operator found which takes a left-hand operand of type 'const MyClass' (or there is no acceptable conversion)


Стоит заметить, что ключевое слово "const" в прототип оператора я добавил именно после этой ошибки.

Далее я решил переопределить оператор явно для двух операндов, и в хэдере "MyClass.h"(рядом с MyClass, ведь логично их рядом расположить) написал функцию:

 
Код:
bool operator<(const MyClass obj1, const MyClass obj2)
{
    return onj1.WordId < obj2.WordId;
}


После написания этой функции вообще начался дурдом. Начали появляться следующие ошибки:
Цитата:
error LNK1169: one or more multiply defined symbols found


Это было только два раза.

и

Цитата:
error LNK2005: "bool __cdecl operator<(class MyClass,class MyClass)" (??M@YA_NVMyClass@@0@Z) already defined in FullHistory.obj


Эта ошибка указывала на "файлы.obj", которые соответствовали классам, где используется MyClass. Таких ошибок было прилично.

Я уже и "extern" помечал эту функцию, и засовывал в дерективы #ifndef - #define - #endif.

Единственный раз, когда у меня получалось скомпилировать программу - это когда я помещал перегрузку оператора с двумя операндами (bool operator<(const MyClass obj1, const MyClass obj2)) в тот файл, где идет работа с std::map.
Но я не считаю это законченным решением. Это что же, мне постоянно переопределять оператор сравнения при каждом обращении к MyClass?

Что скажете?

11
27 января 2012 года
oxotnik333
2.9K / / 03.08.2007
Код:
class MyClass
{
public:
    MyClass(int val)
    {
        WordId = val;
    }
    bool operator<(const MyClass object2) const
    {
        return WordId < object2.WordId;
    }
private:
    unsigned int WordId;
};

int main()
{
    MyClass myClass(10);
    std::map<MyClass, int>container;
    container[myClass] = 10;
    std::map<MyClass, int>::iterator iter = container.find(myClass);
    return 0;
}

Так компиляется.
10K
27 января 2012 года
Cybernetic
106 / / 22.07.2009
То есть нужно было перегрузку оператора пометить как константную функцию?

А еще я для себя заметил, что лучше отдельно компилить сначала либу, а потом второй проект. Что-то у них не срастается, когда их одновременно компилишь.

В любом случае, у меня сейчас тоже компиляется.
240
31 января 2012 года
aks
2.5K / / 14.07.2006
Цитата: Cybernetic
То есть нужно было перегрузку оператора пометить как константную функцию?


Конечно константную. map же использует константные ключи. Вообще странно что подобный вопрос возник. ВСЕ методы, которые не изменяют состояние объекта должны ВСЕГДА описываться как константные. Это же основы!
Объекты, передаваемые в параметры функций по ссылке или указателю, тоже надо передавать как константные, если они не меняются внутри. И объекты надо передавать по ссылке, а не по значению. Иначе каждый раз создается временный объект и происходит копирование в него.
То есть:

 
Код:
bool operator < (const MyClass & object) const;


И да, раз уж объекты используются в качестве элементов контейнеров (да и не только в этом случае) - нужно описать им конструктор копирования и оператор присваивания. Особенно если объект будет не совсем простой.
10K
31 января 2012 года
Cybernetic
106 / / 22.07.2009
Цитата: aks
ВСЕ методы, которые не изменяют состояние объекта должны ВСЕГДА описываться как константные. Это же основы!


Не знал и понимал этого. Да наверное и сейчас не понимаю, зачем обязательно сообщать компилятору, что объект не меняется. И тем более мне не понятно, зачем функцию помечать константной. Что это изменит? Но обязательно учту на будущее.
Спасибо за советы, все приму к сведению.

240
31 января 2012 года
aks
2.5K / / 14.07.2006
Если ты не описываешь метод как константный, ты автоматически запрещаешь его вызов у константного объекта. Иметь константные объекты - вполне обыденно. И запрещать у этих объектов вызывать методы, конторы не меняют состояние объекта - не просто признак плохого тона, а тянет уже на саботаж. =)
Ну тебе бы понравилось, если бы у простого константного объекта ты бы не мог вызвать какой нибудь геттер например?


Цитата: Cybernetic
Не знал и понимал этого. Да наверное и сейчас не понимаю, зачем обязательно сообщать компилятору, что объект не меняется.


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

326
01 марта 2014 года
sadovoya
757 / / 19.11.2005
Цитата:
Во вторых - таким образом ты показываешь пользователю функции, что это входной параметр, который не будет меняться. И что туда можно не опасаясь передавать свои объекты.


Если только какой-нибудь извращенец не напишит что-то вроде этого:

Код:
#include <iostream>

void fun(const int& x) {
    (*const_cast<int*>(&x))*= 2;
}

int main() {
    int y = 1;
    fun(y); //судя по прототипу fun, y не должна меняться
    std::cout << y << std::endl; //ой..
    return 0;
}
Или даже так:

 
Код:
void fun(const int& x) {
   (*(int*)(&x))*= 2; //даже без const_cast
}

Знаете кого-то, кто может ответить? Поделитесь с ним ссылкой.

Ваш ответ

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог