Разработчик ПО
0,0
рейтинг
21 июля 2012 в 00:32

Разработка → Portable Components, кроссплатформенная библиотека для C++ из песочницы

C++*
«Система должна быть спроектирована так,
чтобы оставаться как можно проще
после серии внесенных в нее изменений»

Бьярне Строуструп – программист, автор языка C++

Преамбула


В данной статье мне бы хотелось бы рассказать о довольно популярной, но так редко освещаемой на Хабре библиотеке Portable Components (сокр. POCO). Она будет полезна как разработчикам бизнес-логики программного продукта, так и в решении большинства прикладных задач. При всем изобилии кроссплатформенных библиотек для C++ всё больше людей сталкиваются с POCO лицом к лицу и не знают с чего начать. В данной статье я постараюсь описать технологии, заложенные в библиотеке и дать простейшие примеры решения некоторых задач. Также хотелось бы отметить, что за плечами библиотеки множество успешных как Open Source, так и коммерческих проектов.

Описание


POCO представляет собой коллекцию классов, упрощающих процесс разработки, отладки и тестирования программного продукта. В основе библиотеки лежит принцип модульной системы с малой степенью связности. Как и её коллега Boost, POCO разбита на модули, каждый из которых выполняет свою роль в системе, однако не так усердно использует шаблонную магию парадигму обобщённого программирования как Boost, что позволяет избежать некоторых проблем связанных с поиском ошибок. Еще одним существенным плюсом является размер конечного дистрибутива – размер ядра POCO (Poco Foundation) занимает порядка полутора мегабайт памяти (версия 1.4.3.0, MSVC v100), остальные модули от 50 до 800 КБ, что в современном мире совсем не много даже для встраиваемых систем. Applied Informatics Software Engineering GmbH – разработчик POCO даже заявляют поддержку таких крохотных устройств как Digi Connect ME 9210, выполненных в форм-факторе коннектора RJ-45, имеющего на борту всего 2 или 4 МБ флеш и 8МБ ОЗУ.

POCO ориентирована, в основном, на сетевую разработку и портирована на популярные операционные системы: Windows, Unix, Linux, eLinux, Mac OS X, Solaris, QNX Neutrino, Vxworks, Openvms, Tru64, HP-UX, Android. Данный список довольно быстро расширяется, так как все платформозависимые модули отделены от логики. Фактически, на любую операционную систему, для которой имеется современный компилятор для языка C++, можно портировать POCO.

Библиотека может быть применена как основа к любой разработке, будь то программное обеспечение для сервера или клиента, при этом приложение гарантированно запустится на любой из имеющихся архитектур (признаюсь, иногда не без особой магии). Притом POCO обладает такими мощными средствами как TCP Server Framework, Reactor Framework, которые позволяют очень легко создавать высокопроизводительные WEB-сервера, позволяя нам с вами сэкономить время на разработке. Также в библиотеке присутствует оснастка для создания консольных приложений, демонов Unix, служб Windows. Возможна параллельная работа с такими библиотеками как Qt, wxWidget, GTK+.

Концепции некоторых частей библиотеки позаимствованы из Java Class Library, MS .NET Framework и Apple Cocoa. Это в основном высокоуровневые вещи, такие как управление потоками или таймеры.

Poco написана c строгим соблюдением стандарта языка ANSI/ISO C++ 2003 с помощью стандартной библиотеки C++ и STL. Выпускается под лицензией «Boost Software License», допускающей как коммерческое, так и некоммерческое использование.

Как изучать POCO



Большую часть примеров вы можете найти в исходных кодах, в SDK Reference и презентациях.

Основные модули и примеры использования


Ядро библиотеки

  • Средства динамической типизации данных Any и DynamicAny
    DynamicAny any("99");
    int i = any; // i == 99
    any = 65536;
    string s = any; // s == "65536"
    char c = any; // слишком большое число, вызовется исключение RangeException
    

  • Манипуляции со временем и датой
    const char *date = "05.06.1977"; //Apple 2 birthday
    int Diff;
    DateTime time = DateTimeParser::parse("%d.%m.%Y", date, Diff);
    Timespan diff = DateTime() - time;
    
    cout	<< "Apple 2 существует уже" << diff.days() << " дней с "
    		<< DateTimeFormatter::format(time, "%e %B %Y, %W", Diff) << endl; 
    		// Результат: "5 June 1977, Sunday"
    
    cout	<< "Тот год был "
    		<< (DateTime::isLeapYear(time.year()) ? "високосным" : "не високосным");
    

  • Средства работы с событиями и оповещениями
    #include "Poco/BasicEvent.h"
    #include "Poco/Delegate.h"
    #include <iostream>
    
    using BasicEvent;
    using Delegate;
    
    class Source
    {
    public:
    	BasicEvent<int> theEvent;
    
    	void fireEvent(int n)
    	{
    		theEvent(this, n);
    	}
    };
    
    class Target
    {
    public:
    	void onEvent(const void* pSender, int& arg)
    	{
    		cout << "onEvent: " << arg << endl;
    	}
    };
    
    int main(int argc, char** argv)
    {
    	Source source;
    	Target target;
    
    	//Создаем делегат и добавляем в список Event'ов
    	source.theEvent += Delegate<Target, int>(	
    	&target, &Target::onEvent);
    
    	//Отправляем событие
    	source.fireEvent(42);	
    
    	//Разделегируем
    	source.theEvent -= Delegate<Target, int>(
    	&target, &Target::onEvent);
    
    	return 0;
    }
    

  • Обработка регулярных выражений
    RegularExpression regular("([0-9]+) ([0-9]+)");
    
    vector<string> arr;
    regular.split("123 456", 0, arr); //arr = {“123 456”, ”123”, ”456”}
    
    string s = "123 456";
    regular.subst(s, "$2 $1"); // s == "456 123"
    

  • Средства работы с динамически-подключаемыми библиотеками.
    SharedLibrary lib("C:\\Windows\\System32\\shell32.dll");
    if (lib.isLoaded() && lib.hasSymbol("Control_RunDLL"))
    {
    	auto fun = static_cast<void (*)()>(lib.getSymbol("Control_RunDLL"));
    
    	fun(); //Открываем панель управления
    
    	lib.unload();
    }
    

  • Средства управления памятью
    //Умные указатели
    class A {};
    class B : public A {} ;
    class C : public A {};
    …
    SharedPtr<A> pA;
    SharedPtr<B> pB(new B);
    pA = pB;	// Возможно, B подкласс A
    pA = new B;	// Капельку полиморфизма
    
    // pB = pA;	 // Нельзя, у SharedPtr запрет прямого копирования
    pB = pA.cast<B>();	// а так можно
    SharedPtr<C> pC(new C);
    pB = pC.cast<B>();	// pB теперь null
    
    //Динамическая фабрика
    DynamicFactory<A> factory;
    
    factory.registerClass<B>("B"); // создаем Instantiator<B, A>
    factory.registerClass<C>("C"); // создаем Instantiator<C, A>
    
    
    SharedPtr<A> pA = factory.createInstance("B");
    SharedPtr<A> pB = factory.createInstance("C");
    
    factory.unregisterClass("C");
    
    bool isA = factory.isClass("B"),			// true
    isB = factory.isClass("C"),			// false (не зарегистрирован)
    isC = factory.isClass("habrahabr");	// false (да вы что?!)
    
    //Буфер
    Buffer<char> buffer(1024);	// Создаем буфер на 1024 элемента
    cin.read(buffer.begin(), buffer.size()); // Читаем эти 1024 элемента из stdin
    streamsize n = cin.gcount();	 
    string s(buffer.begin(), n);	// Формируем строку из принятых данных
    cout << s << endl;	// Профит
    
    //Пул памяти
    MemoryPool pool(1024); // Неограниченное число 1024 байтных блоков
    // MemoryPool pool(1024, 4, 16); // До 16 блоков; 4 выделить заранее
    
    char* buffer = static_cast<char*>(pool.get());	//Получаем буфер из пула
    cin.read(buffer, pool.blockSize());	//Считываем из stdin один блок
    streamsize n = cin.gcount();
    string s(buffer, n); //Составляем строку
    pool.release(buffer); //Отчищаем строку
    
    cout << s << endl; //Профит
    
    
    

  • Синглтоны
    class Singleton
    {
    public:
    	int add(int i, int p) { return i+p; }
    	static Singleton& instance()
    	{
    		static SingletonHolder<Singleton> single;
    		return *single.get();
    	}
    };
    …
    int res = Singleton::instance().add(1,2);
    

  • Средства форматирования строк
    //printf-style formating
    string str = format("In %[0]d was %[1]s of %[2]s %[3]d", 
    						DateTime(1977,6,5).year(),	// %[0]d
    						string("b-day"),	// %[1]s
    						string("Apple"),	// %[2]s 
    						2); 				// %[3]d
    //str = “In 1977 was b-day of Apple 2”
    

  • Информация о системе и работа с переменными окружения
    cout	<< "Операционная система: " << Environment::osName()
    << "\nВерсия ОС: " << Environment::osVersion()
    << "\nАрхитектура: " << Environment::osArchitecture()
    << "\nИден. пользователя: " << Environment::nodeName()
    << "\nMAC-адрес: " << Environment::nodeId();
    
    if (Environment::has("HOME"))
    cout << "\nДомашняя дир.: " << Environment::get("HOME") << endl;
    
    Environment::set("POCO", "foo");	//Устанавливаем переменную окружения POCO=foo
    


Сжатие данных

  • Средства для реализации потокового сжатия данных
  • Средства для создание ZIP файлов
    ofstream zipper("text.gz", ios::binary);
    ofstream text("text.txt", ios::binary);
    
    text << "Hello my little computer world. I can zip this string. It's wonderful.";
    text.close();
    
    Zip::Compress zipc(zipper,true);
    zipc.addFile (Path("text.txt"), "text.txt");
    zipc.close();
    
    ifstream dezipper("text.gz", ios::binary);
    poco_assert (dezipper);
    Zip::Decompress zipd(dezipper,Path().append("\\text.dz"));
    zipd.decompressAllFiles();
    



Криптография

  • Генератор псевдослучайных чисел
    Random rnd;
    rnd.seed();
    
    cout	<< "Целочисленное: " << rnd.next()
    		<< "\nЦелочисленное: " << rnd.next(10)
    		<< "\nБайт: " << rnd.nextChar()
    		<< "\nБит: " << rnd.nextBool()
    		<< "\nПлавающее с дв. точностью: " << rnd.nextDouble();
    
    RandomInputStream ri;
    string rs;
    ri >> rs;
    

  • Механизм создания ХЭШ-ей
    string message("Это секретное послание никто не должен разгадать");
    string passphrase("anl!sfsd9!_3g2g?f73");	//Делаем сильный пароль
    
    //HMAC = Hash-based message authentication code ;)
    HMACEngine<SHA1Engine> encoder(passphrase);
    encoder.update(message);	//Хэшируем
    
    //С помощью encoder.digest() получаем вектор байт
    string encodedstr(DigestEngine::digestToHex(encoder.digest()));
    
    //Хэшируем MD5 поток
    MD5Engine md5;
    DigestOutputStream ostr(md5);
    
    ostr << "Это секретное послание никто не должен разгадать";
    ostr.flush();
    
    //Получаем результат в HEXе
    string result = DigestEngine::digestToHex(md5.digest());
    

  • Поддержка сертификатов X509
  • Механизмы шифрования данных
  • Потоковая криптография
  • Поддержка OpenSSL


Базы данных

  • Взаимодействие с различными базами данных (SQLite, MySQL, ODBC, etc)
    Data::SQLite::Connector::registerConnector();
    Data::Session ses("SQLite", "mydb.db");
    
    int count = 0;
    ses << "SELECT COUNT(*) FROM PERSON", into(count), now;
    cout << "People in DB " << count;
    
    string firstName("Петр";
    string lastName("Иванов");
    int age = 0;
    ses << "INSERT INTO PERSON VALUES (:fn, :ln, :age)", 
    		use(firstName), use(lastName), use(age), now;
    ses << "SELECT (firstname, lastname, age) FROM Person", 
    		into(firstName), into(lastName), into(age, -1), now;
    
    Data::SQLite::Connector::unregisterConnector();
    

  • Пул сессий
  • RecordSet
    Statement select(session);
    select << "SELECT * FROM Person";
    select.execute();
    RecordSet rs(select);
    

  • Кортежи
    struct Person
    {
    	string fullname, city;
    	size_t age;
    };
    …
    typedef Tuple<string, string, int> Person;
    
    vector<Person> people;
    people.push_back(Person("Bart Simpson", "Springfield", 12));
    people.push_back(Person("Lisa Simpson", "Springfield", 10));
    
    Statement insert(session);
    insert << "INSERT INTO Person VALUES(:name, :address, :age)", use(people), now;
    


Файловая система

  • Платформонезависимая работа с файлами и директориями
    Path p_wind("C:\\Windows\\system32\\cmd.exe");
    Path p_unix("/bin/sh");
    
    p_wind = "projects\\poco";
    p_unix = "projects/poco";
    
    p_unix.parse("/usr/include/stdio.h", Path::PATH_UNIX);
    
    bool ok = p_unix.tryParse("/usr/*/stdio.h");
    ok = p_unix.tryParse("/usr/include/stdio.h", Path::PATH_UNIX);
    ok = p_unix.tryParse("/usr/include/stdio.h", Path::PATH_WINDOWS);
    ok = p_unix.tryParse("DSK$PROJ:[POCO]BUILD.COM", Path::PATH_GUESS);


Работа с логами

  • Мощное средство управления логами
  • Форматирование логов
  • Каналы передачи логов
    //Простой файловый логгер
    AutoPtr<SimpleFileChannel> pChannel(new SimpleFileChannel);
    pChannel->setProperty("path", "log.log");
    pChannel->setProperty("rotation", "2 K");
    Logger::root().setChannel(pChannel);
    
    Logger& logger = Logger::get("TestLogger"); // Получаем логгер TestLogger
    
    for (int i = 0; i < 13; ++i)
    	logger.information("Это сообщение выведется 13 раз");
    
    
    //Расширенный файловый логгер
    AutoPtr<FileChannel> pChannel(new FileChannel);
    pChannel->setProperty("path", " log.log");
    pChannel->setProperty("rotation", "2 K");
    pChannel->setProperty("archive", "timestamp");
    Logger::root().setChannel(pChannel);
    
    Logger& logger = Logger::get("TestLogger"); // Получаем логгер TestLogger
    
    for (int i = 0; i < 13; ++i)
    	logger.information("Это сообщение выведется 13 раз");
    
    //Асинхронный консольный логгер
    AutoPtr<ConsoleChannel> pCons(new ConsoleChannel);
    AutoPtr<AsyncChannel> pAsync(new AsyncChannel(pCons));
    
    Logger::root().setChannel(pAsync);
    
    Logger& logger = Logger::get("TestLogger"); // Получаем логгер TestLogger
    
    for (int i = 0; i < 13; ++i)
    	logger.information("Это сообщение выведется 13 раз");
    
     
    
    //Консольно-файловый логгер
    AutoPtr<ConsoleChannel> pCons(new ConsoleChannel);
    AutoPtr<SimpleFileChannel> pFile(new SimpleFileChannel("test.log"));
    AutoPtr<SplitterChannel> pSplitter(new SplitterChannel);
    
    pSplitter->addChannel(pCons);
    pSplitter->addChannel(pFile);
    
    Logger::root().setChannel(pSplitter);
    Logger::root().information("Выводим в файл и на консоль");
    
    Logger& logger = Logger::get("TestLogger");
    LogStream lstr(logger);
    lstr << " Выводим в файл и на консоль через поток" << endl;
    
    //Форматированный лог
    AutoPtr<ConsoleChannel> pCons(new ConsoleChannel);
    AutoPtr<PatternFormatter> pPF(new PatternFormatter);
    
    //Формат "Год-месяц-день час:минута:секунда отправитель: текст"
    pPF->setProperty("pattern", "%Y-%m-%d %H:%M:%S %s: %t");
    
    AutoPtr<FormattingChannel> pFC(new FormattingChannel(pPF, pCons));
    
    Logger::root().setChannel(pFC);
    Logger::get("TestChannel").information("Форматированый вывод в консоль");
    

Многопоточность

  • Платформонезависимая поддержка потоков и пулов потоков
    //Наследуемся от Runnable. Hello JAVA.
    class ThreadRunner: public Runnable
    {
    	virtual void run()
    	{
    		cout << "Это сообщение выведено из нового треда" << endl;
    	}
    };
    
    //Ни от чего не наследуюемся
    class ThreadRunnerNoRunnable
    {
    	void norun()
    	{
    		cout << "Это сообщение выведено из нового треда" << endl;
    	}
    };
    
    …
    ThreadRunner runnable;
    Thread thread;
    
    thread.start(runnable); //Запускаем тред
    thread.join(); //Ждем его завершения
    
    ThreadRunnerNoRunnable norunnable;
    RunnableAdapter< ThreadRunnerNoRunnable > 
    runnable2(norunnable, & ThreadRunnerNoRunnable::norun);
    
    Thread thread2; 
    Thread2.start(norunnable); //Запускаем тред
    Thread2.join(); //Ждем его завершения
    
    //Пул тредов
    class ThreadRunner: public Runnable
    {
    	virtual void run()
    	{
    		static int num;
    		cout << "Это сообщение выведено из нового треда " << endl;
    		for (int i=0; i<100; ++i)
    			++num;
    	}
    };
    …
    ThreadRunner runnable1, runnable2, runnable3;
    
    //Запускаем потоки
    ThreadPool::defaultPool().start(runnable1);
    ThreadPool::defaultPool().start(runnable2);
    ThreadPool::defaultPool().start(runnable3);
    
    //Ждем их выполнения
    ThreadPool::defaultPool().joinAll();
    

  • Средства синхронизации потоков
    
    class ThreadRunner: public Runnable
    {
    public:
        ThreadRunner(int &num, Mutex& mutex)
            : num(num), mutex(mutex)
        {}
            
        virtual void run()
        {
            while (num < 100)
            {
                ScopedLock<Mutex> lock(mutex); //Если уберем, то получится чахорда
                for (int i=0; i<5; ++i)
                    cout << "TID:" << Thread::currentTid() << " NUM:" << ++num << endl;
                            
                Thread::sleep(100);
            } 
        }
    private:
        int& num;
        Mutex& mutex;
    };
    ...
    int num = 0;
    Mutex mutex;
    
    Thread th1;
    ThreadRunner tr1(num,mutex);
    th1.start(tr1);
    
    while (num < 100)
    {   
        ScopedLock<Mutex> lock(mutex); //Если уберем, то получится чахорда
        for (int i=0; i<5; ++i)
            cout << "TID:" << Thread::currentTid() << " NUM:" << ++num << endl;
        Thread::sleep(100);
    } 
    
    th1.join();
    
    

  • Рабочие очереди
  • Таймеры
  • Менеджер задач
  • Active Objects: Activities и Active Methods

Сетевые технологии

  • Сокеты
    Net::SocketAddress sa("www.habrahabr.ru", 80);
    Net::StreamSocket socket(sa);
    Net::SocketStream str(socket);
    str << "GET / HTTP/1.1\r\n"
    "Host: habrahabr.ru\r\n"
    "\r\n";
    
    str.flush();
    StreamCopier::copyStream(str, cout);
    
    //Слушающий сокет
    Net::ServerSocket srv(8080); // Биндим и начинаем слушать
    while(true)
    {
    	Net::StreamSocket ss = srv.acceptConnection();
    	{
    		Net::SocketStream str(ss);
    		str << "HTTP/1.0 200 OK\r\n"
    		"Content-Type: text/html\r\n"
    		"\r\n"
    		"<html><head><title>Доброго времени суток</title></head>"
    		"<body><h1><a href=\"http://habrahabr.ru\">Добро пожаловать на Хабр.</a></h1></body></html>"
    		<< flush;
    	}
    }
    

  • Многопоточные серверы
  • DNS
    const HostEntry& entry = DNS::hostByName("www.habrahabr.ru");
    cout << "Каноническое имя: " << entry.name() << endl;
    
    const HostEntry::AliasList& aliases = entry.aliases();
    for (HostEntry::AliasList::const_iterator it1 = aliases.begin(); it1 != aliases.end(); ++it1)
    	cout << "Хост: " << *it1 << endl;
    
    const HostEntry::AddressList& addrs = entry.addresses();
    for (HostEntry::AddressList::const_iterator it2 = addrs.begin(); it2 != addrs.end(); ++it2)
    	cout << "IP: " << it2->toString() << endl;
    

  • Клиенты для некоторых протоколов прикладного уровня (FTP, SMTP, etc.)
  • HTTP(S)-сервер, HTTP аутентификация
  • Компилятор С++ кода — вставок HTML, обработка форм HTML, MIME
  • Поддержка URI, UUID
  • Поддержка RFC 6455
  • Поддержка SSL/TLS

Процессы

  • Манипуляции с процессами (запуск, остановка)
    cout << "Мой PID: " << Process::id() << endl;
    vector<string> args;
    args.push_back("shell32");
    args.push_back("ShellAboutA");
    
    Process::launch("rundll32", args);
    

  • Синхронизация процессов
  • Механизм общей памяти
    File file("Shared.dat");
    
    SharedMemory mem(file, SharedMemory::AM_READ);
    cout << &*mem.begin() << endl;
    


Потоковые операции

  • Потоковое кодирование/декодирование BASE-64, HexBinary
    Base64Encoder encoder(cout);
    encoder << "Это сообщение закодируется в Base64 и выведется в stdout";
    

  • Потоки ввода вывода в память
  • Поддержка URI-потоков
    Net::HTTPStreamFactory::registerFactory();
    auto_ptr<istream> input(
    	URIStreamOpener::defaultOpener().open("http://habrahabr.ru")
    );
    
    cout << input->rdbuf();
    


Кодирование текста

  • Поддержка кодирование в/из UTF-8 и Unicode
    string utf8("Это UTF-8 строка.");
    UTF8Encoding decoder;
    
    TextIterator end(utf8);
    
    for (TextIterator iter(utf8, decoder); iter != end; ++iter)
    	int unicode = *iter;
    

  • Поддержка конвертирования кодировок
    string latin("Это Latin1 строка.");
    
    Latin1Encoding decoder;
    UTF8Encoding encoder;
    
    OutputStreamConverter converter(cout, decoder, encoder);
    converter << latin << endl; //Теперь latin - UTF-8 строка
    


Utility

  • Фреймворк для создания консольных и серверных приложений.
  • Поддержка аргументов командной строки

Конфигурирование

  • Создание Unix-daemons и сервисов Windows

XML

  • Поддержка DOM, SAX2
  • Поддержка как режим чтения, так и режим записи


Заключение


В заключение хотелось бы отметить, что описание некоторых модулей было опущено вследствие того, что модули эти заслуживают отдельного внимания и требуют отдельных статей. Я искренне верю, что у данной библиотеки есть светлое будущее. Также хотелось бы видеть в POCO некоторые плюшки из нового стандарта C++11.
Следующей статьей хотелось бы рассказать о специфичных вещах в POCO. Буду рад объективным замечаниям и возражениям.
Спасибо за прочтение.
Дмитрий @nephrael
карма
28,0
рейтинг 0,0
Разработчик ПО
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (40)

  • +1
    Пару дней назад ковырял эту либу — понравилась. А тут статейка — спасибо! ))
  • +5
    Есть ли у этой библиотеки какие-нибудь плюсы по сравнению с Qt? Я вижу, у них довольно сильно пересекается функциональность.
    • +3
      Лиценция, позволяющая коммерческое использование, отсутствие необходимости в MOC, и, может быть, некоторая легковесность, хотя это спорный вопрос.
      • +1
        Тогда, стОит рассмотреть ещё U++. Он отвечает всем указанным критериям при, скажем так, более компактном коде.
        • 0
          Ни разу не встречал её в дикой природе, да и гуй там совсем уж формошлепный на выходе.
          • 0
            U++ — библиотека на любителя, но крайне гибкая и мощная, если научиться пользоваться.
            В остальном — просто не хочу оффтопить. И гуй, и поддержка всего от быстрых контейнеров до SSL, там не просто есть, а очень сильно есть. )
            • +2
              Использую U++ в своих проектах. Могу сказать, что на первый взгляд U++ выглядит достаточно простовато, однако, когда начинаешь копать детали, то понимаешь, что библиотека очень мощная и необычная. Чего стоит pick семантика, которая необходима для получения более быстрого кода, встроенный lock-free аллокатор с возможностью отлова утечек памяти. И все это уже встроено в библиотеку!
              • +3
                Сюда же сверхбыстрые строки и контейнеры, нативная поддержка json, xml и прочего.
                А так же, моя библиотека сверхбезопасной многопоточности на sequential processes.
                Извините, не удержался.)
                • +2
                  Как я был бы рад обзорной статье об U++…
                  • +1
                    В фреймворк заложено такое количество интересных идей, что одной статьёй вряд ли можно будет просто их адекватно перечислить.
                    Только что написал статью, посвящённую идеологии управления ресурсов в U++. За счёт неё удаётся побеждать всю или почти всю головную боль с утечками памяти.
      • +6
        LGPL тоже позволяет коммерческое использование, если что.
        • +2
          К сожалению для разработки под iOS использовать LGPL нельзя — так как apple не дает возможности делать динамические библиотеки
          • 0
            Эм. Они именно запретили их использовать подгрузку исполняемого кода из других файлов в том же бандле, или же просто нет технической возможности? Если второе, то почему до сих пор не написан лоадер?
          • +1
            Ради справедливости, LGPL можно линковать статически при условии распространения объектных файлов. Но да, по факту в данном случае LPGL почти невозможно использовать.
    • +5
      Я думаю их не корректно сравнивать, ввиду того, что Qt является тяжёлой универсальной библиотекой ориентированной на создание клиентских приложений с GUI, в то время как POCO является легковесной и ориентирована на сетевое программирование.
      Однако если сравнивать QtCore и POCO Foundation (ядра Qt и POCO), то тут несомненно первый плюс — шаблонная магия POCO вместо moc у QT, остальное — дело вкуса. Я считаю, что и на Qt можно создать профессиональный продукт, и на POCO, просто такие вещи как создание высоконагруженных и высоконадежных процессинг серверов я бы доверил именно POCO.
      • +2
        Сигналы слоты в новом Qt5 тоже на шаблонах делаются, хотя старый синтаксис оставлен. В результате слотом может быть обьявлена любая вообще функция, вне зависимости от того, есть moc или нет его.
        Вот для сигналов по прежнему moc нужен, как нужен он для интроспекции нормальной и для биндингов к другим ЯП.
  • +2
    Все руки не доходили посмотреть.
    Многое, конечно, уже есть в новом стандарте (генераторы случайных чисел, многопоточность причем с барьерами, кортежи, регулярки), но вот работа с динамическими библиотеками и процессами, сжатие через потоки, кодирование текста (хотя тут все равно без ICU с ее таблицами на 14 мб не обойтись) и всякие сетевые штуки — это сладко-сладко, да.

  • +2
    Есть одна особенность этой библиотеки: весь unicode представлен с помощью std::string, внутри которых лежат строки utf-8. Используя внутри юникодный winapi, poco автоматом делает преобразование. Для классов которые работают с именами файлов — poco не принимает std::wstring или wchar_t*. В помощь есть класс UnicodeConverter.
    • 0
      Скажите, неймспес std и классы string, vector, istream тут именно от PoCo? Или используется хитрая мешанина с STL? Выглядят они откровенно чужеродными, да и смысла нет использовать сразу две кросс-платформенные библиотеки и/или два синтаксиса.

      Ощущения от статьи: интересно, надо будет попробовать. Не раскрыта работа с коллекциями, XML, смутило разное форматирование параметров в format, Statement, PatternFormatter, но это не беда. Также появилось легкое предчуствие, что портирование таого зверя на новые ОС далеко не тривиально и если надо запустить код на каких-нибудь QNX/BeOS/iOS, то придется слать письма счастья разработчикам и ждать долгими зимними вечерами.
      • 0
        По поводу пространств имен: строки, вектора и потоки — все тут STL. POCO сама по себе построена на STL и не дублирует её функционал, поэтому особых накладных расходов на использование 2ух библиотек одновременно нет.

        По поводу некоторой незаконченности статьи — так и задумано, тема привлекла внимание к себе и все пропуски в этой статье будут, конечно же, заполнены.В данный момент я уже пишу статью по Application'ов, после этого будет и все остальное.

        Насчет переносимости — это вечная проблема, насколько мне известно, сейчас только тандем Win/Lin/Mac ведет себя одинаково процентов на 90%.
        • +1
          только тандем Win/Lin/Mac ведет себя одинаково процентов на 90%
          Так мало? Или статистика отфанарная?
          • +1
            Статистика из личного опыта. На FreeBSD жалуются, что не заводится. На QNX пробовал собрать, не получилось, бросил и особо не вникал в проблему.
            А у этого тандема периодически случаются косяки и скорей всего я занизил число опираясь на багтрекер. Так что статистика скорее не отфанарная, а субъективная.
            • 0
              Т.е. получается, что кроссплатформенность существенно хромает. Не радует :( А как дела обстоят с различными компиляторами не подскажете?
              • +2
                В основном — порты GCC на разные платформы и Вендовый MSVC. Но я не думаю, что нельзя использовать другие. Как никак писалось с соблюдением стандартов и по сути нужны только C++03 совместимый компилятор, STL, а также для потоков и сокетов либо POSIX API, либо WinAPI.
  • +1
    Я бы поправил пример с мьютексами, потому-что в приведенном примере мьютексы не выполняют свою роль — они ничего не защищают.
    • 0
      Спасибо за замечание, поправил код.
  • +1
    Очень аккуратно выглядит, хотя почти всё это есть в Qt, поэтому думаю в сочетании с Qt это все будет излишеством, но как легковесная замена Бусту думаю сгодится.
  • –6
    блин, что ж они не используют правила именования как в STL и Boost (там все маленькими буквами)?

    Ну и имхо у немцев ОГРОМНЫЕ проблемы с архитектурами софта. Глядя на кривость API KDE (проектировали немецкие студенты), убогость и кривизну OpenOffice — есть ощущение что это у них в крови, и что POCO — такая же по-немецки кривая.
    • +1
      Может из за то что в немецком языке все существительные пишутся с большой буквы -отсюда и такое наименование (предположение)
  • 0
  • +2
    Недавно начал использовать POCO в рабочем проекте в качестве легковесной альтернативы Qt и собственным велосипедам. Пока всем доволен, но целостного мнения ещё не сложилось.

    Буду рад, если публикации по библиотекам будут время от времени появляться на Хабре :)
  • +1
    А как её прикрутить к QtCreator`у? Никак не получается скомпилить пример genrsakey.
    • 0
      Если на Windows, то компилируем POCO утилитой buildwin.cmd (к примеру так buildwin 100 build shared debug x64 nosamples), заранее нужна скомпилированая библиотека OpenSSL. Далее создаем проект. В файл проекта вписываем пути к include директориями POCO и OpenSSL в переменную INCLUDEPATH, подключить либы через переменную LIBS, и соответственно при запуске в PATH должны находится пути к местам, где лежат либы POCO и OpenSSL
      Подробней по переменным на доках Qt
      • 0
        Да я, собственно, так и делаю. Однако ж линкер всё равно ругается.
        Поправка: пути к либам лучше прописывать в виде -L<path>, а не в системную PATH.
        • 0
          Может это POCO_STATIC?
          • 0
            Да нет, shared. Собирал с помощью build_vs100.cmd.
        • 0
          Я собрал так:
          POCO_PATH =     c:/mingw/poco
          OSSL_PATH =     c:/openssl/
          INCLUDEPATH +=  $$POCO_PATH/include $$OSSL_PATH/include
          LIBS +=         -L$$POCO_PATH/lib64/ -L$$OSSL_PATH/lib/ \
                          -lPocoCryptod -lPocoFoundationd -lPocoUtild \
                          -llibeay32mdd -lssleay32mdd -lws2_32 -liphlpapi
          
          • 0
            Кстати собираю инклуды в коневой папке я вот так: «cp -r */include .» (cp из msys)

            Либо можно заменить инклуд так
            INCLUDEPATH +=  $$POCO_PATH/CppUnit/include/	\
                    $$POCO_PATH/Crypto/include/	\
                    $$POCO_PATH/Data/include/	\
                    $$POCO_PATH/Foundation/include/	\
                    $$POCO_PATH/Net/include/	\
                    $$POCO_PATH/Util/include/	\
                    $$POCO_PATH/XML/include/	\
                    $$POCO_PATH/Zip/include/
            
            • 0
              В общем, я сдаюсь. Видимо так сложились звёзды…
    • +2
      Проблема решена переопределением флага Zc:wchar_t, по умолчанию он выключен.

      QMAKE_CXXFLAGS += /Zc:wchar_t
      

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.