Здравствуйте, lboss, Вы писали:
L>Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, ГоночныйВолк со товарищи!
CS>А вот у меня вопрос возник:
CS>На кой ляд все эти танцы с бубнами?
CS>
WH>Это мелочи... Но имена _* и __* насколько я помню зарезервированы для разработчиков компилятора.
В стандарт смотреть не хочу, т.к. его всё равно у меня нет , но вот из Deep C++ вписанной в MSDN:
The rules differ slightly between the two languages. In C90 and C99, the implementation reserves
any global-scope name beginning with _.
any name beginning with _ followed by an upper-case letter.
any name beginning with __.
In C++, the implementation reserves
any global-scope name beginning with _.
any name beginning with _ followed by an upper-case letter.
any name containing __.
Здравствуйте, c-smile, Вы писали:
CS>Первое. Стандартных сообщений не много. десяток. ну может два.
Во-первых, я ничего не знаю про твою реализацию, поэтому в предыдущем сообщении говорил про реализацию WinLib с relisoft.com, а там сообщений много.
Но это не важно, т.к. я уже сказал — vtable — это мелочь. В шаблонных обработчиках статические инициализаторы карт сообщений тоже немало места скушают, однако здесь размер зависит только от количества обрабатываемых классом сообщений.
L>Все сообщения должны быть прописаны ЧАСТНЫМ образом в ProcessMessage. CS>Тут я не понял совсем... Опять в плену мифа о множественности сообщений?
Все сообщения (не важно, много или мало) нужно взламывать в библиотеке и вызывать конкретные обработчики или, как у тебя, обработчики категорий. Т.е. вся обработка параметров сообщений (т.е. взлом сообщений) намертво зашита в библиотеку. Мне, лично, это не нравится.
А в шаблонном варианте взломщик можно специалировать где угодно и как угодно. Можно даже специализировать по классу окон (например MsgSpec<DummyWindow,WM_PAINT>:Msg<WM_PAINT>), чтобы иметь возможность добавлять (или наоборот убирать) что-то совсем специфическое для конкретного класса, но не в обработчик, а во взломщик.
L>Ошибка в одной букве в имени, или неправильный порядок аргументов при переопределении обработчика — и прощай надёжность. Каждый раз нужно заглядывать в библиотечное определение и проверять, так ли ты написал. CS>Не понял. Ты про что? Ты вообще С++ имеешь ввиду, кстати?
Конечно С++, что же ещё? Или у тебя редактор умеет подсвечивать виртуальные функции, не входящие в базовый класс? (Хотя можно посмотреть в дереве, но всё равно искать). Компилятор не может тебя предупредить, что ты определил новую виртуальную функцию on_mmove(ButtonState,KeyState) или wm_mousemove(KeyState,ButtonState) вместо переопределения wm_mousemove(ButtonState,KeyState). Я именно это имел в виду. Хотя в твоём варианте с on(mouse_event&) эта проблема вроде исчезает, однако, по-моему, появляется другая: при добавлении в дочернем классе одной новой функции on(death_for_all&) компилятор прячет все старые on(...).
L>Монолитность старого кода — очень хреново. CS>А это ошибка проектирования и ни что другое. CS>Никакие templates и пр. эту проблему не решают.
Любой монолитный код, каким бы удобным и хорошо спроектированным он не был по-началу, будет когда-нибудь нуждаться в переписывании. Монолитность — bad, это у некоторых уже в определениях, в том числе и у меня.
CS>Я уже лет шесть по разными GUI подходами занимаюсь...
И хорошо.
А вообще, подводя итог:
Давай закроем тему? Это бесполезный спор. Каждый останется при своём мнении и будет пользовать тем, что ему удобнее. Тем более, что я не хочу яростно защищать ни один из существующих методов обработки сообщений — у каждого своих недостатков предостаточно.
Если есть удобный рабочий вариант с виртуальными обработчиками категорий сообщений, то запости в Исходники. Он будет для кого-нибудь действительно полезнее шаблонных обработчиков.
Здравствуйте, c-smile, Вы писали: CS>Про WTL не надо. Это партизанская либа для использования в глыбоком тылу врага.
У моего друга на работе основные библиотеки ATL и WTL. Очень крупная фирма. Чего ж тут партизанского?
CS>Под поддержкой ты имеешь ввиду конструкции вида: CS>MESSAGE_HANDLER(WM_CREATE, OnCreate);
Это вообще гадость — в каждом обработчике все параметры вручную обрабатывать.
CS>class window — то что в Win32 называется topmost window. CS>class widget — то что называется child window. CS>Очевидно что эти два класса имеют совершенно разные системы событий, например: CS>window::on(event_activate& evt); и widget::on(event_keyboard& evt);
Кхм. А если у меня дочернее окно с заголовком, то это куда? Как в WinRAR окно рас/запаковки, или как почти все docking windows.
Здравствуйте, lboss, Вы писали:
L>"с разделением исходника на файлы" — это вообще не связанно... Это аналогично статической функции внутри класса — просто генерится перекрывающийся сегмент — линкер оставляет только один из них...
Угу, проверил — работает. Просто у меня в памяти остались глюки с такими трюками в старых компиляторах.
Кстати, совсем забыл указать на явную ошибку приводящую к большому leak-у в каждой карте сообщений. std::map::operator[] предназначен не для доступа, а для создания новой пары. Он создаёт новую пару с заданным ключом, и возвращает ссылку на второй элемент в паре. Константного метода не сделали специально, чтобы не было путаницы.
Здравствуйте, c-smile, Вы писали: CS>Я уже лет шесть по разными GUI подходами занимаюсь... CS>И вот в результате вернулся к истокам: http://terra-informatica.org/j-smile CS>Получил массу удовольствия имплементируя.
Кстати, удовольствие удовольствием, но j-smile demo не закрывает процесс при закрытии окна — приходится его вручную убивать. Смотрел на Win2k.
А контролы — приятные, ничего не скажешь.
L>Кстати, совсем забыл указать на явную ошибку приводящую к большому leak-у в каждой карте сообщений. L>std::map::operator[] предназначен не для доступа, а для создания новой пары. Он создаёт новую пару с заданным ключом, и возвращает ссылку на второй элемент в паре. Константного метода не сделали специально, чтобы не было путаницы.
Боюсь и тут ты не прав — да создается новая пара — но(!) она вносится в список — и соответственно во второй раз она и возвращается (и соответственно разрушается в деструкторе) — ни какой утечки... В моём коде плюс — не вызваются лишние конструкторы итераторов, минус — замедляется поиск — так что и так и так правильно — но я подумал что с operator [] будет понятней...
Здравствуйте, lboss, Вы писали:
L>Боюсь и тут ты не прав — да создается новая пара — но(!) она вносится в список — и соответственно во второй раз она и возвращается (и соответственно разрушается в деструкторе) — ни какой утечки... В моём коде плюс — не вызваются лишние конструкторы итераторов, минус — замедляется поиск — так что и так и так правильно — но я подумал что с operator [] будет понятней...
"Не надо ля-ля"
Такую интереснейшую схему неявных карт сообщений привёл, что никому и в голову не приходила, а на таких простых вещах путаешься. в карте сообщений нужно столько записей, сколько есть обработчиков сообщений. Если больше — уже утечка. Ну и что, что она потом "возвращается". Если тебя не устраивает термин "утечка", можно использовать "чрезмерное использование ресурсов" — всё равно плохо.
сообщения окну могут слаться самые разные — никто не гарантирует, что только 200 стандартных. В частности, любой может зарегистрировать именованое сообщение в системе и использовать его для опознавания "свой-чужой" (если не больше). А попробовать цикл с посылкой сообщений от 1 до 1000000000 ты пробовал? Вылет гарантирован.
Кстати, std::map жрёт память намного быстрее Loki::AssocVector-а из-за не-in-place хранения объектов и дополнительных расходов на указатели.
какие ещё "лишние конструкторы итераторов"??? Сравни в асме _map.find() и _map[]. Все эти "лишние конструкторы итераторов" есть и в варианте с "доступом" через _map[], только с довеском в виде создания ненужных пар. К тому же, ты сам говоришь, что "замедляется поиск". А для чего доступ-то требуется? Только для поиска обработчика.
Здравствуйте, limax, Вы писали:
L>Кстати, удовольствие удовольствием, но j-smile demo не закрывает процесс при закрытии окна — приходится его вручную убивать. Смотрел на Win2k.
Бага известная. Концепт кары вообще как правило мотора не имеют .
Здравствуйте, limax, Вы писали:
L>"Не надо ля-ля" L>Такую интереснейшую схему неявных карт сообщений привёл, что никому и в голову не приходила, а на таких простых вещах путаешься.
За похвалу спасибо. За критику тоже, но:
L> L>в карте сообщений нужно столько записей, сколько есть обработчиков сообщений. Если больше — уже утечка. Ну и что, что она потом "возвращается". Если тебя не устраивает термин "утечка", можно использовать "чрезмерное использование ресурсов" — всё равно плохо.
Утечка (Leak) — это здесь — оновное это то что оно рушит программу — так как ресурс расходуется не возвратно...
В данном случае — это не leak!!! Но в любом случае — повторю — я привёл реализацию для более понятного кода...
L>сообщения окну могут слаться самые разные — никто не гарантирует, что только 200 стандартных. В частности, любой может зарегистрировать именованое сообщение в системе и использовать его для опознавания "свой-чужой" (если не больше). А попробовать цикл с посылкой сообщений от 1 до 1000000000 ты пробовал? Вылет гарантирован.
Ох... Запусти и глянь — думаю ты очень удивишься...
Код сгенерён Wizard'ом — я добавил 3 строчки (затаганы <Vadim>):
// Test1.cpp : Defines the entry point for the application.
//#include"stdafx.h"#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:#include <windows.h>
// C RunTime Header Files#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <map>
#include"resource.h"#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text
// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_TEST1, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_TEST1);
// Main message loop:while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_TEST1);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_TEST1;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
TCHAR szHello[MAX_LOADSTRING];
//<Vadim>static std::map<UINT, bool> allMsg;
allMsg[message] = true;
_stprintf(szHello, _T("%u"), allMsg.size());
//</Vadim>switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
RECT rt;
GetClientRect(hWnd, &rt);
DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
L>Кстати, std::map жрёт память намного быстрее Loki::AssocVector-а из-за не-in-place хранения объектов и дополнительных расходов на указатели.
В данном случае это не очень важно...
L>какие ещё "лишние конструкторы итераторов"??? Сравни в асме _map.find() и _map[]. Все эти "лишние конструкторы итераторов" есть и в варианте с "доступом" через _map[], только с довеском в виде создания ненужных пар. К тому же, ты сам говоришь, что "замедляется поиск". А для чего доступ-то требуется? Только для поиска обработчика. L>
Это ты привязался к реализации... Map в быстрой реализации работает без итераторов... а find() и end() конструируют и разрушают итераторы (и тоже проводят поиск как и operator[])... Другое дело, что это хорошо оптимизится... Но опять говорю — ты прав — в реальности там проще hash table поюзать... Опять таки в стандартный STL она не входит — поэтому я для наглядности map привел...
Здравствуйте, lboss, Вы писали:
L>Утечка (Leak) — это здесь — оновное это то что оно рушит программу — так как ресурс расходуется не возвратно... L>В данном случае — это не leak!!! Но в любом случае — повторю — я привёл реализацию для более понятного кода...
Давай разбираться. Любая утёкшая память освобождает операционной системой при закрытии программы. До закрытия, утечки могут (и вероятно будут) только накапливаться.
Память выделенная статической карте сообщений будет освобождена только при закрытии программы. До закрытия, размер карты может (и вероятно будет) только увеличиваться.Я не вижу разницы между первым и вторым для пользователя, так какой толк в определении утечек?
Поэтому считаю такие расходы неприемлимыми.
L>Ох... Запусти и глянь — думаю ты очень удивишься...
Ничего удивительного. В большинстве случаев расширения карты будут незначительными, но никто не гарантирует, что они такими и останутся в каждом случае — потенциально карта может расти до объёма всей памяти. Я уже привёл пример новых сообщений. Так зачем писать недетерминированный код?
L>Это ты привязался к реализации... Map в быстрой реализации работает без итераторов... а find() и end() конструируют и разрушают итераторы (и тоже проводят поиск как и operator[])... Другое дело, что это хорошо оптимизится...
Не совсем понял смысл. В какой это быстрой реализации map работает без итераторов?
Вот выдержка из реализация std::map в VC7.1
mapped_type& operator[](const key_type& _Keyval)
{ // find element matching _Keyval or insert with default mapped
iterator _Where = this->lower_bound(_Keyval);
if (_Where == this->end() || this->comp(_Keyval, this->_Key(_Where._Mynode())))
_Where = this->insert(_Where,
value_type(_Keyval, mapped_type()));
return ((*_Where).second);
}
iterator find(const key_type& _Keyval)
{ // find an element in mutable sequence that matches _Keyval
iterator _Where = lower_bound(_Keyval);
return (_Where == end() || this->comp(_Keyval, _Key(_Where._Mynode()))
? end() : _Where);
}
И там, и там, используется итератор+lower_bound
Для сравнения, Loki::AssocVector — аналогично:
// 23.3.1.2 element access:
mapped_type& operator[](const key_type& key)
{ return insert(value_type(key, mapped_type())).first->second; }
// modifiers:
std::pair<iterator, bool> insert(const value_type& val)
{
bool found(true);
iterator i(lower_bound(val.first));
if (i == end() || this->operator()(val.first, i->first))
{
i = Base::insert(i, val);
found = false;
}
return std::make_pair(i, !found);
}
// 23.3.1.3 map operations:
iterator find(const key_type& k)
{
iterator i(lower_bound(k));
if (i != end() && this->operator()(k, i->first))
{
i = end();
}
return i;
}
L>Но опять говорю — ты прав — в реальности там проще hash table поюзать... Опять таки в стандартный STL она не входит — поэтому я для наглядности map привел...
Когда это я про хеш говорил??
Для карты сообщений, отсортированный массив или бинарное дерево подходит как нельзя лучше. Конструируется она один раз, а двоичный поиск гарантирует почти везде одинаковую скорость поиска. Что такое логарифм — так, пшик один. Для карты из 100 сообщений максимум 7 сравнений, для 1000 — 10, для миллиона — 20
Кстати, у меня остался вопрос. В форуме С/С++ его WolfHound задал, но пока никто на него не ответил.
Почему тип возвращаемого значения конструируется заранее, а тип параметров — нет?
Т.е. в RetType<T> func (ParamType<T>) RetType сконструируется, а ParamType — нет.
Это стандартное явление? Как ты на него вообще вышел?
Я тут покумекал — если это стандарт, то открываются довольно богатые возможности использования шаблонов С++, т.к. частично компенсируется отсутствие статических конструкторов. Вот только жаль, что типы параметров не конструируются.
Здравствуйте, limax, Вы писали:
L> L>Любая утёкшая память освобождает операционной системой при закрытии программы. До закрытия, утечки могут (и вероятно будут) только накапливаться. L>Память выделенная статической карте сообщений будет освобождена только при закрытии программы. До закрытия, размер карты может (и вероятно будет) только увеличиваться. L>Я не вижу разницы между первым и вторым для пользователя, так какой толк в определении утечек? L>Поэтому считаю такие расходы неприемлимыми.
Нет — основное отличие leak от неоптимального использования памяти в том, что при leak — программа в конечном итоге съедает всю памать и грохается... Это разные задачи — leak — это серъёзный баг, а неоптимальность — просто завышенные требования к ресурсам...
L><skip/> Так зачем писать недетерминированный код?
Сто раз уже сказал — для наглядности... Я вообще свой hash (он не добавляет элементы если не надо (а-ля lookup в MFC)) юзаю и не жужу...
L>Не совсем понял смысл. В какой это быстрой реализации map работает без итераторов? L>Вот выдержка из реализация std::map в VC7.1
Разачарую тебя, в VC по моему (и не только по моему) самая поганая реализация STL из тех что я видел...
Обычно пишется что-то вроде:
SecondType & operator[] (const KeyType & key)
{
TreePair * p = m_root;
<Поиск по дереву (целиком на указателях)>
<если не найдено - то вставка>
return p->second;
}
iterator find(const KeyType & key)
{
TreePair * p = m_root;
<Поиск по дереву (целиком на указателях)>
return iterator(p);
}
Итератор коструируется толкько в самом конце...
В любом случае — это всё лирика...
L>Но опять говорю — ты прав — в реальности там проще hash table поюзать... Опять таки в стандартный STL она не входит — поэтому я для наглядности map привел...
L>Когда это я про хеш говорил??
Ты прав в том, что это не оптимальный алгоритм...
L>Для карты сообщений, отсортированный массив или бинарное дерево подходит как нельзя лучше. Конструируется она один раз, а двоичный поиск гарантирует почти везде одинаковую скорость поиска. Что такое логарифм — так, пшик один. Для карты из 100 сообщений максимум 7 сравнений, для 1000 — 10, для миллиона — 20
Ох и зачем ты меня логаритмам учищь? Или это буря восторга?... Но всё равно, Hash лучше — тут довольно предсказуемые значения hash-функцию постоить можно классную...
L>Кстати, у меня остался вопрос. В форуме С/С++ его WolfHound задал, но пока никто на него не ответил. L>Почему тип возвращаемого значения конструируется заранее, а тип параметров — нет? L>Т.е. в RetType<T> func (ParamType<T>) RetType сконструируется, а ParamType — нет.
Что значит зарание? Ни чего там зарание не конструируется...
А насчет WolfHound — пусть читает стандарт — шаблоны расскрываются по мере надобности и того что не надо генерить не генерится....
L>Это стандартное явление? Как ты на него вообще вышел?
Я 12 лет уже на C++ программаю
L>Я тут покумекал — если это стандарт, то открываются довольно богатые возможности использования шаблонов С++, т.к. частично компенсируется отсутствие статических конструкторов. Вот только жаль, что типы параметров не конструируются.
Конструируются... Просто в точке вызова — если эту функцию кто-то позовет то в той точке и будет развёрнут шаблон...
Пропускаю про утечки. L>Ох и зачем ты меня логаритмам учищь? Или это буря восторга?...
А как же
L>Но всё равно, Hash лучше — тут довольно предсказуемые значения hash-функцию постоить можно классную...
А примерчик можно? И сколько может потребоваться времени на поиск в худшем случае? Если больше того самого логарифма, то меня уже не устраивает. Насколько больше потребуется памяти по сравнению с отсортированноым массивом-картой?
У меня с хешами опыта маловато (если вообще можно сказать, что есть).
Li>Почему тип возвращаемого значения конструируется заранее, а тип параметров — нет? Li>Т.е. в RetType<T> func (ParamType<T>) RetType сконструируется, а ParamType — нет. L>Что значит зарание? Ни чего там зарание не конструируется... L>шаблоны расскрываются по мере надобности и того что не надо генерить не генерится....
Если так, почему твоя идея с картами сообщений вообще работает? Ведь все эти обработчики никто не вызывает, если не сконструировать типы их возвращяемых значений. Замкнутый круг.
Здравствуйте, limax, Вы писали:
L>Но всё равно, Hash лучше — тут довольно предсказуемые значения hash-функцию постоить можно классную... L>А примерчик можно? И сколько может потребоваться времени на поиск в худшем случае? Если больше того самого логарифма, то меня уже не устраивает. Насколько больше потребуется памяти по сравнению с отсортированноым массивом-картой? L>У меня с хешами опыта маловато (если вообще можно сказать, что есть).
Это лучше книжки почитать — но скажу сразу, что int значения самые удобные и хорошо изученные для hash.
L>Если так, почему твоя идея с картами сообщений вообще работает? Ведь все эти обработчики никто не вызывает, если не сконструировать типы их возвращяемых значений. Замкнутый круг.
смотри:
class A
{
void f(Templ<int> a)
{
}
Templ<int> f1()
{
return Templ<int>();
}
};
Здравствуйте, lboss, Вы писали:
L>>Не совсем понял смысл. В какой это быстрой реализации map работает без итераторов? L>>Вот выдержка из реализация std::map в VC7.1
L>Разачарую тебя, в VC по моему (и не только по моему) самая поганая реализация STL из тех что я видел...
L>Обычно пишется что-то вроде:
L>
L>SecondType & operator[] (const KeyType & key)
L>{
L> TreePair * p = m_root;
L> <Поиск по дереву (целиком на указателях)>
L> <если не найдено - то вставка>
L> return p->second;
L>}
L>iterator find(const KeyType & key)
L>{
L> TreePair * p = m_root;
L> <Поиск по дереву (целиком на указателях)>
L> return iterator(p);
L>}
L>
Итератор — это ведь может быть класс с одним полем, указателем. Соответственно, время работы с ним (конструирование/копирование/уничтожение) вроде не должно отличаться от скорости работы с указателем (компилятор все проинлайнит, т.е реализация с итератором и указателем не будут отличаться). Или это не так?
И еще: Твое утверждение насчет поганной STL у VC обоснованно для VC7.1? Т.е, имеет ли смысл менять STL у VC7.1?
7. О чем невозможно говорить, о том следует молчать.
Здравствуйте, WFrag, Вы писали:
WF>Итератор — это ведь может быть класс с одним полем, указателем. Соответственно, время работы с ним (конструирование/копирование/уничтожение) вроде не должно отличаться от скорости работы с указателем (компилятор все проинлайнит, т.е реализация с итератором и указателем не будут отличаться). Или это не так?
WF>И еще: Твое утверждение насчет поганной STL у VC обоснованно для VC7.1? Т.е, имеет ли смысл менять STL у VC7.1?