Помнится еще Александреску в одной из своих книг упоминал как может сортированный vector или deque по скорости поиска элементов превосходить std::set и std::multiset. В последних контейнерах идет большой оверхед по размеру потребляемой памяти, из-за чего процессору приходится больше данных читать из памяти. Недостаток сортированных vector/deque при вставке - слишком часто придется двигать элементы, если вставлять сразу в нужное место. Однако часто вставка идет большой порцией элементов, что позволяет сначала накидать новые элементы как попало (через push_back), а потом отсортировать контейнер.
Что удивительно, ни в boost, ни в Loki я подобного сортированного вектора в виде отдельного класса (шаблона классов) не нашел. В Loki есть подобная штука - AssocVector, но реализует она функциональность не set/multiset, а map. Тоже, кстати, весьма полезная вещь.
Google навел меня на класс с нужной функциональностью на сайте codeproject. Однако там он какой-то сыроватый, VC++-only, да и без набора юнит-тестов, так что использовать его в реальном проекте я бы не стал. Те, кому наплевать на сырость могут вполне его использовать, а к более продвинутым людям просьба сделать подобную вещь нормально и пропихнуть ее таки в boost, т.к. предыдущие "пропихиватели" похоже не справились (см. здесь и здесь).
Остальные же могут использовать std::vector и std::deque, просто сортируя их и получая прирост производительности (по сравнению с std::set/multiset). Ключевых функций для написания будет две: insert и find. Их можно легко реализовать через родные сердцу алгоритмы бинарного поиска - std::lower_bound() и std::upper_bound().
Ссылка по теме: Why you shouldn't use set (and what you should use instead)
28 мая 2007
26 мая 2007
XML Data Binding in C++
Статья An Introduction to XML Data Binding in C++ на The C++ Source напоминает, что DOM И SAX - уже прошлый век, и давно уже пора мапить XML-данные на C++-классы.
Суть такова: пишите XML Schema для своих XML, некая утилита (binding compiler) автоматически генерирует по нему C++-классы, с которыми намного приятнее общаться, нежели, например с DOM:
XML:
C++:
Суть такова: пишите XML Schema для своих XML, некая утилита (binding compiler) автоматически генерирует по нему C++-классы, с которыми намного приятнее общаться, нежели, например с DOM:
XML:
<person>
<name>John Doe</name>
<gender>male</gender>
<age>32</age>
</person>
C++:
ifstream ifs ("person.xml");
auto_ptr<person_t> p = person (ifs);
if (p->age () > 30)
cerr << p->name () << endl;
24 мая 2007
Interview with A. Stepanov
Интересное интервью с Александром Степановым, главным идеологом и создателем STL. Особенно примечательно как он не любит ООП в общем и Java в частности.
19 мая 2007
Loki:ScopeGuard
Александреску - умный парень, но наверно скорее теоретик, чем практик. Иначе как объяснить такое:
В Loki можно найти полезную вещь - scope guard. Поясню зачем она нужна. Все знакомы с RAII и с тем, что очень удобно делать работу по управлению ресурсами в деструкторе - это безопасно с точки зрения исключений, так как при откате стека по исключению вызываются деструкторы всех уничтожаемых объектов. Например:
Однако создавать такие RAII-классы для каждого случая - довольно муторная работа. Представьте:
А ведь дядька Александреску мог бы и пожалеть людей и написать так:
А ведь не написал. Видимо не использовал это в реальных проектах. Или у него там сплошные
PS. Оказывается уже исправили.
В Loki можно найти полезную вещь - scope guard. Поясню зачем она нужна. Все знакомы с RAII и с тем, что очень удобно делать работу по управлению ресурсами в деструкторе - это безопасно с точки зрения исключений, так как при откате стека по исключению вызываются деструкторы всех уничтожаемых объектов. Например:
class FileФайл закроется даже в случае если Foo бросит исключение.
{
public:
File(const char* FileName) { OpenFile(FileName); }
~File() { CloseFile(); }
};
{
File f("test.txt");
Foo();
}
Однако создавать такие RAII-классы для каждого случая - довольно муторная работа. Представьте:
{Гораздо проще было бы жить, если бы можно было записать все это намного короче:
class Guard
{
public:
Guard(Module& M, Window& W) : m(M), w(W) {}
~Guard() { w.Close(); m.Terminate(); }
private:
Window& w;
Module& m;
}
Guard g(module, window);
Foo();
}
{Так вот предложенная Александреску конструкция такое счастье и привносит в нашу жизнь, выглядит это так:
AutoGuard(window.Close());
AutoGuard(module.Terminate());
Foo();
}
{Все бы замечательно, но это не компилируется без
LOKI_ON_BLOCK_EXIT_OBJ(window, Windows::Close);
LOKI_ON_BLOCK_EXIT_OBJ(module, Module::Terminate);
Foo();
using namespace Loki
, так как макрос LOKI_ON_BLOCK_EXIT_OBJ выглядит так:#define LOKI_ON_BLOCK_EXIT_OBJ ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = MakeObjGuard
А ведь дядька Александреску мог бы и пожалеть людей и написать так:
#define LOKI_ON_BLOCK_EXIT_OBJ ::Loki::ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = ::Loki::MakeObjGuard
А ведь не написал. Видимо не использовал это в реальных проектах. Или у него там сплошные
using namespace xxx
стоят?PS. Оказывается уже исправили.
15 мая 2007
WinMain
Объявление WinMain имеет вид:
lpCmdLine имеет тип LPSTR, а по хорошему нужно бы LPTSTR (или даже LPCTSTR, но не суть). Кстати, GetCommandLine() возвращает LPTSTR.
argv тоже все держит в ANSI кодировке, видимо для совместимости со старым кодом. Но для создания юникодной версии парсить командную строку вручную не обязательно - можно воспользоваться CommandLineToArgvW().
int WINAPI WinMain(Не видите ничего странного?
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
);
lpCmdLine имеет тип LPSTR, а по хорошему нужно бы LPTSTR (или даже LPCTSTR, но не суть). Кстати, GetCommandLine() возвращает LPTSTR.
argv тоже все держит в ANSI кодировке, видимо для совместимости со старым кодом. Но для создания юникодной версии парсить командную строку вручную не обязательно - можно воспользоваться CommandLineToArgvW().
12 мая 2007
Windows Sysinternals
Много полезных Windows-разработчику и администратору утилит можно найти на сайте Sysinternals, в частности RegMon и Process Explorer.
10 мая 2007
When edit control sends WM_CTLCOLORSTATIC
Edit control при отрисовке своего фона шлет свому "родителю" сообщение WM_CTLCOLOREDIT, в качестве результата получает HBRUSH, которым и рисует свой фон. Static контролы шлют WM_CTLCOLORSTATIC. Однако, бывают ситуации, когда и Edit запрашивает фон через WM_CTLCOLORSTATIC. Это происходит в двух случаях:
1. когда контрол заблокирован - EnableWindow(Edit, FALSE)
2. когда контрол в режиме read-only - SendMessage(Edit, EM_SETREADONLY, TRUE)
Чтобы read-only edit выглядел не как заблокированный а как обычный контрол, родителю нужно перехватить WM_CTLCOLORSTATIC и подменить его на WM_CTLCOLOREDIT:
1. когда контрол заблокирован - EnableWindow(Edit, FALSE)
2. когда контрол в режиме read-only - SendMessage(Edit, EM_SETREADONLY, TRUE)
Чтобы read-only edit выглядел не как заблокированный а как обычный контрол, родителю нужно перехватить WM_CTLCOLORSTATIC и подменить его на WM_CTLCOLOREDIT:
LRESULT SomeWindow::OnCtlColorStatic(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)Можно также использовать технику message reflection, перенеся выбор фона с родителя на сам edit control.
{
// paint read-only edits as usual edits
return DefWindowProc(IsWindowEnabled((HWND)lParam) ? WM_CTLCOLOREDIT : WM_CTLCOLORSTATIC, wParam, lParam);
}
Подписаться на:
Сообщения (Atom)