Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > map с числом элементов больше двух


Автор: TheDestroyer 18.6.2009, 18:58
Подскажите плз, есть данные: логин - пасс, id, time. Т.е. одному ключу соответствует более одной записи. Необходимо хранить их в массиве и при необходимости сравнивать пары, например логин - пасс (id и time не учитывать). Это было бы возможно при использовании map, но там к сожалению возможно в одну запись вставить только ключ - значение, а у меня значений для ключа более одного. Можно было бы в качестве значения для ключа использовать струтуру, заданную мной, но тогда для сравнения данных надо заполнять структуру полностью и уже после сравнивать. Возможны случаи когда мне известно что-то одно и надо поэтой информации вытащить остальное о логине. Есть ли что-то вроде map, но для бОльшего числа значений для ключа? 

Автор: mes 18.6.2009, 19:04
хранить ключ как структуру и написать предикат/ы для поиска по неполной структуре

Добавлено через 1 минуту и 29 секунд
а лучше имхо хранить не в мапе.

Автор: Cheloveck 18.6.2009, 19:31
Написать контейнер самому проще всего. И определить в нём перегруженный оператор сравнения.

Автор: mes 18.6.2009, 20:18
Цитата(Cheloveck @  18.6.2009,  18:31 Найти цитируемый пост)
Написать контейнер самому проще всего. И определить в нём перегруженный оператор сравнения. 

перегрузить в контейнере ?  чтоб сравнивать два контейнера ? а это разве требуется ?
если имелась ввиду структура (класс), то перегруженный оператор будет сравнивать только для одного пункта, а требуется для разных (несколько вариантов).
 smile 

Автор: Cheloveck 18.6.2009, 20:49
Цитата(mes @  18.6.2009,  21:18 Найти цитируемый пост)
перегрузить в контейнере ?  чтоб сравнивать два контейнера ?

чтоб сравнивать с чем-то другим... например парой логин-пас...

Ну не обязательно именно operator ==, можно ведь и метод написать compare какой-небудь. Это я так, в общем виде сказал.

Автор: zim22 18.6.2009, 20:58
Цитата(mes @  18.6.2009,  20:18 Найти цитируемый пост)
перегруженный оператор будет сравнивать только для одного пункта, а требуется для разных

мне в голову мысль ударила, может и неправильнаяsmile
а что если алгоритмы вынести за пределы класса (использовать паттерн Strategy)?

Автор: mes 18.6.2009, 21:32
Цитата(zim22 @  18.6.2009,  19:58 Найти цитируемый пост)
мне в голову мысль ударила, может и неправильнаяsmile
а что если алгоритмы вынести за пределы класса (использовать паттерн Strategy)? 

а нельзя ли пояснения к этому  ?


Цитата(Cheloveck @  18.6.2009,  19:49 Найти цитируемый пост)
можно ведь и метод написать compare какой-небудь. Это я так, в общем виде сказал.

Зачем писать это в классе, когда можно сделать снаружи ;)
Тогда если соблюсти подход стл, то
1. Можно  будет не меняя класса добавить предикат для любого нужного сравнения
2. Использовать готовые алгоритмы.
3.. 
smile

Автор: zim22 18.6.2009, 22:57
Цитата(mes @  18.6.2009,  21:32 Найти цитируемый пост)
а нельзя ли пояснения к этому  ?

я это так представляю:
main.cpp
Код

#include "Composition.h"
#include "IdDateCompositor.h"
#include "IdPasswordTime.h"
#include "LoginTimeCompositor.h"
#include "user_info.h"

int main()
{
  user_info user[3]  = {
    {1, "ivan", "pass33", 15},
    {2, "zina", "kakad3", 19},
    {3, "zhora", "dlsfd", 33}
  };
  
  Composition *id_date = new Composition(new IdDateCompositor);
  bool isEq = id_date->Compare(user[0], user[1]);

  Composition *id_password_time = new Composition(new IdPasswordTime);
  isEq = id_password_time->Compare(user[1], user[2]);

  Composition *login_time = new Composition(new LoginTimeCompositor);
  isEq = login_time->Compare(user[0], user[2]);

    return 0;
}



LoginTimeCompositor.h
Код

#ifndef _LOGINTIME_COMPOSITOR_H_
#define _LOGINTIME_COMPOSITOR_H_

class LoginTimeCompositor : public Compositor {
public:
  LoginTimeCompositor() {}

  virtual bool Equal(user_info &lhs, user_info &rhs) { 
    return (lhs.login == rhs.login && lhs.time == rhs.time);
  }
};
#endif // _LOGINTIME_COMPOSITOR_H_

Composition.h
Код

#ifndef _COMPOSITION_H_
#define _COMPOSITION_H_

class Compositor;
struct user_info;

class Composition {
public:
  Composition(Compositor *ptr) : _compositor(ptr) {}
  bool Compare(user_info&, user_info&);
private:
  Compositor *_compositor;
};

#endif // _COMPOSITION_H_

Compositor.h
Код

#ifndef _COMPOSITOR_H_
#define _COMPOSITOR_H_

class Compositor {
public:
  virtual bool Equal(user_info &lhs, user_info &rhs) = 0;
protected:
  Compositor(){}
};

#endif // _COMPOSITOR_H_

IdDateCompositor.h
Код

#ifndef _IDDATE_COMPOSITOR_H_
#define _IDDATE_COMPOSITOR_H_

#include "Compositor.h"
#include "user_info.h"

class IdDateCompositor : public Compositor {
public:
  IdDateCompositor(){}

  virtual bool Equal(user_info &lhs, user_info &rhs) { 
    return (lhs.user_id == rhs.user_id && lhs.time == rhs.time);
  }
};

#endif // _IDDATE_COMPOSITOR_H_

IdPasswordTime.h
Код

#ifndef _IDPASSWORDTIMECOMPOSITOR_H_
#define _IDPASSWORDTIMECOMPOSITOR_H_

class IdPasswordTime : public Compositor {
public:
  IdPasswordTime() {}
  virtual bool Equal(user_info &lhs, user_info &rhs) { 
    return (lhs.user_id == rhs.user_id && lhs.password == rhs.password && 
            lhs.time == rhs.time);
  }
};

#endif // _IDPASSWORDTIMECOMPOSITOR_H_

user_info.h
Код

#ifndef _USER_INFO_H
#define _USER_INFO_H

struct user_info {  
  int user_id;
  char *login;
  char *password;
  int time;
};
#endif // _USER_INFO_H

Composition.cpp
Код

#include "Composition.h"
#include "Compositor.h"

bool Composition::Compare(user_info &lhs, user_info &rhs) {  
  return _compositor->Equal(lhs, rhs);  
}


Автор: mes 18.6.2009, 23:57
а если проще ? например так :
Код

enum eUserInfOMask
{
     eLogin = 1<<0,
     ePass  = 1<<1,
     eTime  = 1<<2
};

struct SUserInfo
{
    std::string Login;
    std::string Pass;
    std::string Time;
};

template<int mask> bool equal (const SUserInfo& us1, const SUserInfo& us2)
{
    return ( (mask & eLogin) == eLogin ? us1.Login == us2.Login  : true )
       &&  ( (mask & ePass)  == ePass  ? us1.Pass  == us2.Pass   : true )
       &&  ( (mask & eTime)  == eTime  ? us1.Time  == us2.Time   : true );
};

int main(int argc, const char** argv) {

    SUserInfo  us1, us2;
    us1.Login = "login";
    us2.Login = us1.Login;
    us1.Pass =  "Pass1";
    us2.Pass = "Pass2";

    std::cout << std::boolalpha
              << equal<eLogin> (us1,us2) <<  std::endl
              << equal<eLogin| ePass> (us1,us2)<< std::endl;

    return 0;
}

 smile 

P.S. к тому же все расчеты по стратегии и лишние сравнения останутся в компил тайм.
если ж требуется динамичность, то можно заменить на обычную функцию с передачей стратегии как аргумент.


Автор: W4FhLF 19.6.2009, 05:08
http://www.boost.org/doc/libs/1_39_0/libs/multi_index/doc/index.html


Автор: zim22 19.6.2009, 08:02
Цитата(mes @  18.6.2009,  23:57 Найти цитируемый пост)
а если проще ?

ничего против не имею. интересный подход с использованием enum.  smile 
Цитата(mes @  18.6.2009,  23:57 Найти цитируемый пост)
P.S. к тому же все расчеты по стратегии и лишние сравнения останутся в компил тайм.

Strategy тоже можно реализовать в виде шаблона. 

Автор: Lazin 19.6.2009, 08:34
Цитата(TheDestroyer @  18.6.2009,  18:58 Найти цитируемый пост)
Подскажите плз, есть данные: логин - пасс, id, time. Т.е. одному ключу соответствует более одной записи. Необходимо хранить их в массиве и при необходимости сравнивать пары, например логин - пасс (id и time не учитывать). Это было бы возможно при использовании map, но там к сожалению возможно в одну запись вставить только ключ - значение, а у меня значений для ключа более одного. Можно было бы в качестве значения для ключа использовать струтуру, заданную мной, но тогда для сравнения данных надо заполнять структуру полностью и уже после сравнивать. Возможны случаи когда мне известно что-то одно и надо поэтой информации вытащить остальное о логине. Есть ли что-то вроде map, но для бОльшего числа значений для ключа?

поскольку о 
Цитата(W4FhLF @  19.6.2009,  05:08 Найти цитируемый пост)
boost::multi_index_container
 уже написали, мне остается добавить одно:
хранить пароли и логины в оперативной памяти, в неизменном виде - опасно, вместо этого, лучше хранить их хэш
к примеру, можно использовать такую структуру данных: 
Код

struct AccountInfo
{
    std::string password_hash;//SHA-1 хэш пароля
    int id;
    tm time;
};
std::map< int/*id*/, AccountInfo > user_acc;
std::map< std::string, int/*id*/ >  user_list;

Автор: TheDestroyer 19.6.2009, 09:58
Спасибо за информацию! Буду разбираться.

Автор: jonie 19.6.2009, 19:04
Цитата

уже написали, мне остается добавить одно:
хранить пароли и логины в оперативной памяти, в неизменном виде - опасно
опасно всё. Но ежели кто-то может выцепить логин-пароль из памяти, то каков смысл хеширования? В мире *n?x очень очень много паролей вообще хранятся по определенным путям(!) не то что шифрованные .... в общем я считаю "хранить хеш безопаснее" очень очень спорным утверждением.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)