2015-10-13 2 views
2

У меня есть простая программа для карт. Он занимает класс в качестве ключа. Класс имеет несколько членов. Я полагаю, что моя функция сравнения верна. Я слежу за строгим слабым порядком. Проблема в том, что она позволяет вводить дубликаты ключей.Карта с ключом класса, позволяет дублировать ключи

Ниже приведен мой код.

#include <iostream> 
#include <string.h> 
#include <map> 

class mapkey 
{ 
public: 
    std::string mInterface; 
    std::string mDestination; 
    int   mPrefixLen; 
    std::string mNextHop; 
    int   mMetric; 

    mapkey() {} 
    ~mapkey() {} 
    mapkey(std::string a, std::string b, int c, std::string d, int e) 
    { 
     mInterface = a; 
     mDestination = b; 
     mPrefixLen = c; 
     mNextHop = d; 
     mMetric = e; 
    } 
}; 

struct mapcomp 
{ 
    bool operator() (const mapkey left, const mapkey right); 
}; 

bool mapcomp::operator() (const mapkey left, const mapkey right) 
{ 
    if(strcmp(left.mInterface.c_str(), right.mInterface.c_str()) < 0) 
    return true; 
    if(strcmp(left.mInterface.c_str(), right.mInterface.c_str()) > 0) 
    return false; 

    if(strcmp(left.mDestination.c_str(), right.mDestination.c_str()) < 0) 
    return true; 
    if(strcmp(left.mDestination.c_str(), right.mDestination.c_str()) > 0) 
    return false; 

    if(strcmp(left.mNextHop.c_str(), right.mNextHop.c_str()) < 0) 
    return true; 
    if(strcmp(left.mNextHop.c_str(), right.mNextHop.c_str()) > 0) 
    return false; 

    if(left.mPrefixLen < right.mPrefixLen) 
    return true; 
    if(left.mPrefixLen > right.mPrefixLen) 
    return false; 

    if(left.mMetric < right.mMetric) 
    return true; 
    if(left.mMetric > right.mMetric) 
    return false; 
} 

typedef std::map<mapkey, std::string, mapcomp> script_map; 
script_map mm; 

void print_map() 
{ 
    script_map::const_iterator iter; 
    for (iter = mm.begin(); iter != mm.end(); iter++) 
    { 
    std::cout << "value is - " << iter->second << std::endl; 
    } 
} 

int main() 
{ 
    mapkey test1("eth1", "50.60.70.80", 1, "90.10.20.30", 1); 
    mm[test1] = "first"; 

    mapkey test2("eth1", "50.60.70.40", 1, "90.10.20.30", 1); 
    mm[test2] = "second"; 

    mapkey test3("eth1", "50.60.70.20", 1, "90.10.20.30", 1); 
    mm[test3] = "third"; 

    mapkey test4("eth1", "50.60.70.80", 1, "90.10.20.30", 1); 
    mm[test4] = "fourth"; 

    print_map(); 

    return 0; 
} 

Выше программы, первая и четвертая клавиши такие же. когда я напечатать карту, выход, как показано ниже

г ++ --std = C++ 11 map.cpp

./a.out

значение - третье значение

является - второе значение

это - четвертое значение

это - первый

Что мне не хватает? Четвертая запись не должна быть добавлена.

+4

Таким образом, ваша функция сравнения не верный. – juanchopanza

+5

Что такое все функции C? ['std :: string'] (http://en.cppreference.com/w/cpp/string/basic_string) поставляется с [встроенными операторами сравнения] (http://en.cppreference.com/w/cpp/ строка/basic_string/operator_cmp). Вы также можете использовать ['std :: tie'] (http://en.cppreference.com/w/cpp/utility/tuple/tie) – NathanOliver

+1

Ваш компилятор должен был предупредить вас о сравнении, возможно, не возвращая значение , что происходит, если объекты равны. Если бы это произошло, но вы проигнорировали его, прекратите игнорировать предупреждения. – molbdnilo

ответ

10

Причина: функция сравнения нарушена.

Решение: напишите новый, используя идиоматический C++.

struct mapcomp 
{ 
    bool operator() (mapkey const& l, mapkey const& r) { 
     return 
      std::tie(l.mInterface, l.mDestination, l.mPrefixLen, l.mNextHop, l.mMetric) 
      < 
      std::tie(r.mInterface, r.mDestination, r.mPrefixLen, r.mNextHop, r.mMetric) 
     ; 
    } 
}; 
  • прохожу mapkey const& вместо mapkey, чтобы избежать копирования.
  • Я использую сопоставление кортежей и std::tie, чтобы сделать кортежи из ваших членов.

Вы также должны удалить все конструкторы и деструктор из mapkey. Они не имеют никакой цели, поскольку вы можете инициализировать членов посредством универсальной инициализации.

Я бы также подумал об изменении структуры только для перегрузки operator< (и, возможно, operator==) для вашего класса. Этого достаточно для map, чтобы принять его, не передавая никаких других компараторов.

+0

Они также могут подумать о просто переключении на ['std :: tuple'] (http: //en.cppreference.com/w/cpp/utility/tuple), поскольку он построил в них функции сравнения. – NathanOliver

+0

@NathanOliver, что может означать запись пользовательских тегов доступа. Есть три строки и два ints, было бы легко запутать. –

+0

Да, это было всего лишь предложение. – NathanOliver

0

Начните отсюда:

if(strcmp(left.mInterface.c_str(), right.mInterface.c_str()) < 0) 
    return true; 
if(strcmp(left.mInterface.c_str(), right.mInterface.c_str()) > 0) 
    return false; 

strcmp() возвращает ноль и только ноль, когда строки равны.

Затем посмотрите на первую строку: он возвращает true, прежде чем все остальные участники будут иметь возможность вообще сравниться.

+3

'std :: string' предоставляет' operator ==() 'почему бы не использовать это вместо' 'strcmp()'? –

+1

'std :: string' также предоставляет' operator <() 'и' operator>() ' –

+0

@ AlejandroDíaz, SimonKraemer: По существу. Я просто думаю, что OP, вероятно, студент - и тогда лучше всего найти больше вещей =) – vines

0

Ваш метод mapcomp не возвращает значение во всех случаях. В конце вашей функции требуется окончательное возвращение false, чтобы сигнализировать о том, что элементы равны.

Я предлагаю использовать встроенный в строку < оператора и повторно написать свой метод mapcomp так:

bool mapcomp::operator() (const mapkey& left, const mapkey& right) 
{ 
    if(left.mInterface < right.mInterface) return true; 
    if(left.mInterface > right.mInterface) return false; 

    if(left.mDestination < right.mDestination) return true; 
    if(left.mDestination > right.mDestination) return false; 

    if(left.mNextHop < right.mNextHop) return true; 
    if(left.mNextHop > right.mNextHop) return false; 

    if(left.mPrefixLen < right.mPrefixLen) return true; 
    if(left.mPrefixLen > right.mPrefixLen) return false; 

    if(left.mMetric < right.mMetric) return true; 
    if(left.mMetric > right.mMetric) return false; 

    return false; // items are equal 
} 
0

Для C++, прежде чем вы могли бы использовать

bool mapcomp::operator() (const mapkey left, const mapkey right) 
{ 
    if (left.mInterface != right.mInterface)  return left.mInterface < right.mInterface; 
    if (left.mDestination != right.mDestination) return left.mDestination < right.mDestination; 
    if (left.mNextHop != right.mNextHop)   return left.mNextHop < right.mNextHop; 
    if (left.mPrefixLen != right.mPrefixLen)  return left.mPrefixLen < right.mPrefixLen; 
    if (left.mMetric != right.mMetric)    return left.mMetric < right.mMetric; 
    return false; //equal != less 
} 
Смежные вопросы