<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ars Longa, Vita Brevis &#187; C/C++</title>
	<atom:link href="http://blog.sjinks.pro/c-cpp/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.sjinks.pro</link>
	<description>Quod scripsi, scripsi</description>
	<lastBuildDate>Sat, 19 May 2012 17:55:07 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Отслеживание источника исключения в С++</title>
		<link>http://blog.sjinks.pro/c-cpp/969-track-uncaught-exceptions/</link>
		<comments>http://blog.sjinks.pro/c-cpp/969-track-uncaught-exceptions/#comments</comments>
		<pubDate>Mon, 30 Apr 2012 02:50:20 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[gcc]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=969</guid>
		<description><![CDATA[Лезем в глубокие дебри C++ и его ABI Обобщённая версия статьи «Отслеживание источника исключения в Qt». Решение проблемы отлова не пойманного исключения при помощи gdb — задача не из приятных, особенно при отладке многопоточных приложений. К счастью, есть и более простой способ. Чтобы понять, как организована работа с исключениями на уровне стандартной библиотеки, нужно тщательно выкурить ABI [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/969-track-uncaught-exceptions/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Лезем в глубокие дебри C++ и его ABI</em></h2>
<p>Обобщённая версия статьи «<a href="http://blog.sjinks.pro/c-cpp/qt/964-exception-source-qt/" title="Отслеживание источника исключения в Qt">Отслеживание источника исключения в Qt</a>».</p>
<p>Решение проблемы отлова не пойманного исключения при помощи gdb — задача не из приятных, особенно при отладке многопоточных приложений. К счастью, есть и более простой способ.<span id="more-969"></span></p>
<p>Чтобы понять, как организована работа с исключениями на уровне стандартной библиотеки, нужно тщательно выкурить <abbr title="Application Binary Interface">ABI</abbr> языка C++, в частности, главу, посвящённую <a href="http://sourcery.mentor.com/public/cxx-abi/abi-eh.html">обработке исключений</a>.</p>
<p>Из всей главы нам интересны две функции:</p>
<ol>
<li><span class="codebox"><code class="cpp"><span class="kw4">void</span> __cxa_throw <span class="br0">&#40;</span><span class="kw4">void</span> <span class="sy2">*</span>thrown_exception, std<span class="sy4">::</span><span class="me2">type_info</span> <span class="sy2">*</span>tinfo, <span class="kw4">void</span> <span class="br0">&#40;</span><span class="sy2">*</span>dest<span class="br0">&#41;</span> <span class="br0">&#40;</span><span class="kw4">void</span> <span class="sy2">*</span><span class="br0">&#41;</span> <span class="br0">&#41;</span><span class="sy4">;</span></code></span></li>
<li><span class="codebox"><code class="cpp"><span class="kw4">void</span> __cxa_rethrow <span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span></code></span></li>
</ol>
<p>Первая функция кидает исключение (<code>thrown_exception</code> — кидаемое исключение, <code>tinfo</code> — указатель на информацию о типе исключения (тип <code>std::type_info</code> определён в заголовке <code>&lt;typeinfo&gt;</code>), dest — указатель на деструктор исключения). В принципе, единственное, что нам может быть полезно — это <code>tinfo</code>: <code>tinfo-&gt;name()</code> даст нам имя типа исключения.</p>
<p>Имя исключения будет иметь вид <code>St13runtime_error</code> (<dfn>mangled name</dfn>); для декодирования можно использовать <a href="http://sourcery.mentor.com/public/cxx-abi/abi.html#demangler">функцию</a></p>
<p><span class="codebox"><code class="cpp"><span class="kw4">extern</span> <span class="st0">&quot;C&quot;</span> <span class="kw4">char</span><span class="sy2">*</span> abi<span class="sy4">::</span>__cxa_demangle <span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> mangled_name, <span class="kw4">char</span><span class="sy2">*</span> buf, <span class="kw4">size_t</span><span class="sy2">*</span> n, <span class="kw4">int</span><span class="sy2">*</span> status<span class="br0">&#41;</span><span class="sy4">;</span></code></span></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9697">
        <div class="code cpp" id="p969code7">
<span class="kw4">char</span><span class="sy2">*</span> demangled <span class="sy1">=</span> abi<span class="sy4">::</span> __cxa_demangle<span class="br0">&#40;</span>tinfo<span class="sy2">-</span><span class="sy1">&gt;</span>name<span class="br0">&#40;</span><span class="br0">&#41;</span>, 0, 0, 0<span class="br0">&#41;</span><span class="sy4">;</span><br />
std<span class="sy4">::</span><span class="kw3">cerr</span> <span class="sy1">&lt;&lt;</span> <span class="st0">&quot;Thrown exception of type &quot;</span> <span class="sy1">&lt;&lt;</span> <span class="br0">&#40;</span>demangled <span class="sy4">?</span> demangled <span class="sy4">:</span> tinfo<span class="sy2">-</span><span class="sy1">&gt;</span>name<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy1">&lt;&lt;</span> std<span class="sy4">::</span><span class="me2">endl</span><span class="sy4">;</span><br />
<span class="kw1">if</span> <span class="br0">&#40;</span>demangled<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">free</span><span class="br0">&#40;</span>demangled<span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>При большом желании можно проверить, наследуется ли брошенное исключение от <code>std::exception</code>; если да, то можно вывести на экран значение <code>exception::what()</code>. Проблема здесь в том, что <code>thrown_exception</code> типа <code>void*</code> — как следствие, <code>dynamic_cast</code> не сработает. Поэтому для такой магии придётся разбираться, <a href="http://sourcery.mentor.com/public/cxx-abi/abi.html#rtti">как работает <code>dynamic_cast</code></a>.</p>
<p>Если вкратце, на помощь приходит функция</p>
<p><span class="codebox"><code class="cpp"><span class="kw4">extern</span> <span class="st0">&quot;C&quot;</span> <span class="kw4">void</span><span class="sy2">*</span> __dynamic_cast <span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw4">void</span> <span class="sy2">*</span>sub, <span class="kw4">const</span> abi<span class="sy4">::</span>__class_type_info <span class="sy2">*</span>src, <span class="kw4">const</span> abi<span class="sy4">::</span>__class_type_info <span class="sy2">*</span>dst, std<span class="sy4">::</span><span class="kw4">ptrdiff_t</span> src2dst_offset<span class="br0">&#41;</span><span class="sy4">;</span></code></span></p>
<p>Алгоритм тут такой:</p>
<ol>
<li>Проверить, является ли <code>tinfo</code> экземпляром класса <code>abi::__class_type_info</code>; если нет, то брошенное исключение — не объект.</li>
<li>Привести <code>&#038;typeid(std::exception)</code> к типу <code>const abi::__class_type_info*</code> (преобразование просто должно сработать).</li>
<li>Вызвав <code>__dynamic_cast</code>, проверить, унаследовано ли <code>thrown_exception</code> от <code>std::exception</code>.</li>
</ol>
          
<div class="codebox">
    <div class="the_code" style="" id="p9698">
        <div class="code cpp" id="p969code8">
<span class="kw4">const</span> abi<span class="sy4">::</span>__class_type_info<span class="sy2">*</span> exc <span class="sy1">=</span> <span class="kw2">dynamic_cast</span><span class="sy1">&lt;</span><span class="kw4">const</span> abi<span class="sy4">::</span>__class_type_info<span class="sy2">*</span><span class="sy1">&gt;</span><span class="br0">&#40;</span><span class="sy3">&amp;</span><span class="kw2">typeid</span><span class="br0">&#40;</span>std<span class="sy4">::</span><span class="me2">exception</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="kw4">const</span> abi<span class="sy4">::</span>__class_type_info<span class="sy2">*</span> cti <span class="sy1">=</span> <span class="kw2">dynamic_cast</span><span class="sy1">&lt;</span>abi<span class="sy4">::</span>__class_type_info<span class="sy2">*</span><span class="sy1">&gt;</span><span class="br0">&#40;</span>tinfo<span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="kw1">if</span> <span class="br0">&#40;</span>cti <span class="sy3">&amp;&amp;</span> exc<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">exception</span><span class="sy2">*</span> the_exception <span class="sy1">=</span> <span class="kw2">reinterpret_cast</span><span class="sy1">&lt;</span>std<span class="sy4">::</span><span class="me2">exception</span><span class="sy2">*</span><span class="sy1">&gt;</span><span class="br0">&#40;</span>abi<span class="sy4">::</span>__dynamic_cast<span class="br0">&#40;</span>thrown_exception, exc, cti, <span class="sy2">-</span>1<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>the_exception<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">cout</span> <span class="sy1">&lt;&lt;</span> the_exception<span class="sy2">-</span><span class="sy1">&gt;</span>what<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy1">&lt;&lt;</span> std<span class="sy4">::</span><span class="me2">endl</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Осталось получить backtrace. Здесь нет <a href="http://linux.die.net/man/3/backtrace">ничего сложного</a>.</p>
<p>Вторая функция (<code>__cxa_rethrow</code>) вызывается из catch-блока и кидает обрабатываемое исключение ещё раз. Так как у функции нет аргументов (совсем нет), то бросаемое исключение придётся получать самостоятельно. Для этого используется функция</p>
<p><span class="codebox"><code class="cpp"><span class="kw4">extern</span> <span class="st0">&quot;C&quot;</span> __cxa_eh_globals <span class="sy2">*</span>__cxa_get_globals<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
<span class="kw4">struct</span> __cxa_eh_globals <span class="br0">&#123;</span><br />
&nbsp; &nbsp; __cxa_exception<span class="sy2">*</span> caughtExceptions<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">int</span> uncaughtExceptions<span class="sy4">;</span><br />
<span class="br0">&#125;</span><span class="sy4">;</span></code></span></p>
<p><code>__cxa_exception</code> — заголовок исключения; непосредственно за ним следует бросаемый объект.</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9699">
        <div class="code cpp" id="p969code9">
__cxa_eh_globals<span class="sy2">*</span> g <span class="sy1">=</span> __cxa_get_globals<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="kw1">if</span> <span class="br0">&#40;</span>g <span class="sy3">&amp;&amp;</span> g<span class="sy2">-</span><span class="sy1">&gt;</span>caughtExceptions<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">void</span><span class="sy2">*</span> thrown_exception <span class="sy1">=</span> <span class="kw2">reinterpret_cast</span><span class="sy1">&lt;</span>uint8_t<span class="sy2">*</span><span class="sy1">&gt;</span><span class="br0">&#40;</span>g<span class="sy2">-</span><span class="sy1">&gt;</span>caughtExceptions<span class="br0">&#41;</span> <span class="sy2">+</span> <span class="kw3">sizeof</span><span class="br0">&#40;</span><span class="kw4">struct</span> __cxa_exception<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">type_info</span><span class="sy2">*</span> tinfo &nbsp;<span class="sy1">=</span> g<span class="sy2">-</span><span class="sy1">&gt;</span>caughtExceptions<span class="sy2">-</span><span class="sy1">&gt;</span>exceptionType<span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; <span class="co1">// Далее всё аналогично __cxa_throw</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Всё готово, дело за малым: перехватить вызовы <code>__cxa_throw</code> и <code>__cxa_rethrow</code>. Тут всё просто:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96910">
        <div class="code cpp" id="p969code10">
<span class="co2">#include &lt;dlfcn.h&gt;</span><br />
<br />
<span class="kw4">typedef</span> <span class="kw4">void</span><span class="br0">&#40;</span><span class="sy2">*</span>cxa_throw_type<span class="br0">&#41;</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy2">*</span> , std<span class="sy4">::</span><span class="me2">type_info</span><span class="sy2">*</span>, <span class="kw4">void</span><span class="br0">&#40;</span><span class="sy2">*</span><span class="br0">&#41;</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy2">*</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="kw4">typedef</span> <span class="kw4">void</span><span class="br0">&#40;</span><span class="sy2">*</span>cxa_rethrow_type<span class="br0">&#41;</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
cxa_throw_type &nbsp; orig_cxa_throw &nbsp; <span class="sy1">=</span> <span class="kw2">reinterpret_cast</span><span class="sy1">&lt;</span>cxa_throw_type<span class="sy1">&gt;</span><span class="br0">&#40;</span>dlsym<span class="br0">&#40;</span>RTLD_NEXT, <span class="st0">&quot;__cxa_throw&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
cxa_rethrow_type orig_cxa_rethrow <span class="sy1">=</span> <span class="kw2">reinterpret_cast</span><span class="sy1">&lt;</span>cxa_rethrow_type<span class="sy1">&gt;</span><span class="br0">&#40;</span>dlsym<span class="br0">&#40;</span>RTLD_NEXT, <span class="st0">&quot;__cxa_rethrow&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span>
        </div>
    </div>
</div>

<p>А теперь всё вместе:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96911">
        <div class="code cpp" id="p969code11">
<span class="co2">#include &lt;typeinfo&gt;</span><br />
<span class="co2">#include &lt;exception&gt;</span><br />
<span class="co2">#include &lt;dlfcn.h&gt;</span><br />
<span class="co2">#include &lt;pthread.h&gt;</span><br />
<span class="co2">#include &lt;cstdio&gt;</span><br />
<span class="co2">#include &lt;cstdlib&gt;</span><br />
<span class="co2">#include &lt;inttypes.h&gt;</span><br />
<span class="co2">#include &lt;execinfo.h&gt;</span><br />
<span class="co2">#include &lt;cxxabi.h&gt; // Определяет типы из namespace abi</span><br />
<span class="co2">#include &lt;cstring&gt;</span><br />
<span class="co2">#include &lt;stdexcept&gt;</span><br />
<span class="co2">#include &lt;unistd.h&gt;</span><br />
<br />
<span class="kw2">namespace</span> <span class="br0">&#123;</span> <span class="co1">// Важно: без анонимного пространства имён gcc начинает клинить</span><br />
<br />
<span class="kw4">typedef</span> uint64_t uint64<span class="sy4">;</span> <span class="co1">// В документации тип зовётся uint64</span><br />
<br />
<span class="co1">// Типы/структуры данных из http://sourcery.mentor.com/public/cxx-abi/abi-eh.html</span><br />
<span class="kw4">typedef</span> <span class="kw2">enum</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; _URC_NO_REASON <span class="sy1">=</span> 0,<br />
&nbsp; &nbsp; _URC_FOREIGN_EXCEPTION_CAUGHT <span class="sy1">=</span> 1,<br />
&nbsp; &nbsp; _URC_FATAL_PHASE2_ERROR <span class="sy1">=</span> 2,<br />
&nbsp; &nbsp; _URC_FATAL_PHASE1_ERROR <span class="sy1">=</span> 3,<br />
&nbsp; &nbsp; _URC_NORMAL_STOP <span class="sy1">=</span> 4,<br />
&nbsp; &nbsp; _URC_END_OF_STACK <span class="sy1">=</span> 5,<br />
&nbsp; &nbsp; _URC_HANDLER_FOUND <span class="sy1">=</span> 6,<br />
&nbsp; &nbsp; _URC_INSTALL_CONTEXT <span class="sy1">=</span> 7,<br />
&nbsp; &nbsp; _URC_CONTINUE_UNWIND <span class="sy1">=</span> 8<br />
<span class="br0">&#125;</span> _Unwind_Reason_Code<span class="sy4">;</span><br />
<br />
<span class="kw4">typedef</span> <span class="kw4">void</span> <span class="br0">&#40;</span><span class="sy2">*</span>_Unwind_Exception_Cleanup_Fn<span class="br0">&#41;</span><span class="br0">&#40;</span>_Unwind_Reason_Code reason, <span class="kw4">struct</span> _Unwind_Exception<span class="sy2">*</span> exc<span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
<span class="kw4">struct</span> _Unwind_Exception <span class="br0">&#123;</span><br />
&nbsp; &nbsp; uint64 exception_class<span class="sy4">;</span><br />
&nbsp; &nbsp; _Unwind_Exception_Cleanup_Fn exception_cleanup<span class="sy4">;</span><br />
&nbsp; &nbsp; uint64 private_1<span class="sy4">;</span><br />
&nbsp; &nbsp; uint64 private_2<span class="sy4">;</span><br />
<span class="br0">&#125;</span><span class="sy4">;</span><br />
<br />
<span class="kw4">struct</span> __cxa_exception <span class="br0">&#123;</span><br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">type_info</span><span class="sy2">*</span> exceptionType<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">void</span> <span class="br0">&#40;</span><span class="sy2">*</span>exceptionDestructor<span class="br0">&#41;</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy2">*</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">unexpected_handler</span> unexpectedHandler<span class="sy4">;</span><br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">terminate_handler</span> terminateHandler<span class="sy4">;</span><br />
&nbsp; &nbsp; __cxa_exception<span class="sy2">*</span> nextException<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">int</span> handlerCount<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">int</span> handlerSwitchValue<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> actionRecord<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">const</span> <span class="kw4">char</span><span class="sy2">*</span> languageSpecificData<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">void</span><span class="sy2">*</span> catchTemp<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">void</span><span class="sy2">*</span> adjustedPtr<span class="sy4">;</span><br />
&nbsp; &nbsp; _Unwind_Exception unwindHeader<span class="sy4">;</span><br />
<span class="br0">&#125;</span><span class="sy4">;</span><br />
<br />
<span class="kw4">struct</span> __cxa_eh_globals <span class="br0">&#123;</span><br />
&nbsp; &nbsp; __cxa_exception<span class="sy2">*</span> caughtExceptions<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">int</span> uncaughtExceptions<span class="sy4">;</span><br />
<span class="br0">&#125;</span><span class="sy4">;</span><br />
<br />
<span class="kw4">extern</span> <span class="st0">&quot;C&quot;</span> __cxa_eh_globals<span class="sy2">*</span> __cxa_get_globals<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
<span class="co1">// Тип функции __cxa_throw</span><br />
<span class="kw4">typedef</span> <span class="kw4">void</span><span class="br0">&#40;</span><span class="sy2">*</span>cxa_throw_type<span class="br0">&#41;</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy2">*</span>, std<span class="sy4">::</span><span class="me2">type_info</span><span class="sy2">*</span>, <span class="kw4">void</span><span class="br0">&#40;</span><span class="sy2">*</span><span class="br0">&#41;</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy2">*</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="co1">// Тип функции __cxa_rethrow</span><br />
<span class="kw4">typedef</span> <span class="kw4">void</span><span class="br0">&#40;</span><span class="sy2">*</span>cxa_rethrow_type<span class="br0">&#41;</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
<span class="kw4">static</span> cxa_throw_type &nbsp; orig_cxa_throw &nbsp; <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> <span class="co1">// Адрес оригинальной функции __cxa_throw</span><br />
<span class="kw4">static</span> cxa_rethrow_type orig_cxa_rethrow <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> <span class="co1">// Адрес оригинальной функции __cxa_rethrow</span><br />
<br />
<span class="kw4">static</span> pthread_mutex_t guard <span class="sy1">=</span> PTHREAD_MUTEX_INITIALIZER<span class="sy4">;</span> <span class="co1">// Мьютекс на всякий пожарный</span><br />
<br />
<span class="co1">// Получение трассы вызовов</span><br />
<span class="co1">// Здесь и далее сознательно используются функции из стандартной библиотеки C, так как они не генерируют исключений</span><br />
<span class="co1">// Исключение в низкоуровневом обработчике исключения - это что-то</span><br />
<span class="kw4">static</span> <span class="kw4">void</span> get_backtrace<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">static</span> <span class="kw4">void</span><span class="sy2">*</span> buf<span class="br0">&#91;</span>128<span class="br0">&#93;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw4">int</span> n <span class="sy1">=</span> backtrace<span class="br0">&#40;</span>buf, 128<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">fprintf</span><span class="br0">&#40;</span><span class="kw2">stderr</span>, <span class="st0">&quot;%s<span class="es1">\n</span>&quot;</span>, <span class="st0">&quot;*** BACKTRACE ***&quot;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; backtrace_symbols_fd<span class="br0">&#40;</span>buf, n, STDERR_FILENO<span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
<span class="co1">// Код, приведённый далее, предполагает наличие программ readlink и addr2line</span><br />
<span class="co1">// идея состоит в скармливании адресов, полученных backtrace(3), addr2line(1)</span><br />
<span class="co1">// с целью получения понятного человеку результата</span><br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="kw4">size_t</span> bufsize <span class="sy1">=</span> 19<span class="sy2">*</span>n <span class="sy2">+</span> std<span class="sy4">::</span><span class="kw3">strlen</span><span class="br0">&#40;</span><span class="st0">&quot;/usr/bin/addr2line -pifCa -e `/bin/readlink /proc/XXXXX/exe` 1&gt;&amp;2&quot;</span><span class="br0">&#41;</span> <span class="sy2">+</span> <span class="nu0">1</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">char</span><span class="sy2">*</span> space <span class="sy1">=</span> <span class="kw2">reinterpret_cast</span><span class="sy1">&lt;</span><span class="kw4">char</span><span class="sy2">*</span><span class="sy1">&gt;</span><span class="br0">&#40;</span>std<span class="sy4">::</span><span class="kw3">calloc</span><span class="br0">&#40;</span>bufsize, 1<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>space<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">char</span><span class="sy2">*</span> orig <span class="sy1">=</span> space<span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> c <span class="sy1">=</span> std<span class="sy4">::</span><span class="kw3">sprintf</span><span class="br0">&#40;</span>space, <span class="st0">&quot;/usr/bin/addr2line -pifCa -e `/bin/readlink /proc/%d/exe` &quot;</span>, getpid<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; space <span class="sy2">+</span><span class="sy1">=</span> c<span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw4">int</span> i<span class="sy1">=</span><span class="nu0">0</span><span class="sy4">;</span> i<span class="sy1">&lt;</span>n<span class="sy4">;</span> <span class="sy2">++</span>i<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; c <span class="sy1">=</span> std<span class="sy4">::</span><span class="kw3">sprintf</span><span class="br0">&#40;</span>space, <span class="st0">&quot;%p &quot;</span>, buf<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; space <span class="sy2">+</span><span class="sy1">=</span> c<span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">fprintf</span><span class="br0">&#40;</span><span class="kw2">stderr</span>, <span class="st0">&quot;%s<span class="es1">\n</span>&quot;</span>, <span class="st0">&quot;<span class="es1">\n</span>*** DECODED BACKTRACE ***&quot;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">sprintf</span><span class="br0">&#40;</span>space, <span class="st0">&quot;%s&quot;</span>, <span class="st0">&quot;1&gt;&amp;2&quot;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">fprintf</span><span class="br0">&#40;</span><span class="kw2">stderr</span>, <span class="st0">&quot;%s<span class="es1">\n</span>&quot;</span>, orig<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>std<span class="sy4">::</span><span class="kw3">system</span><span class="br0">&#40;</span>orig<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span> <span class="co1">// Чтобы не ругался gcc</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">free</span><span class="br0">&#40;</span>orig<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="co1">// Обработка исключения, общая для __cxz_throw и __cxa_rethrow</span><br />
<span class="kw4">static</span> <span class="kw4">void</span> handle_exception<span class="br0">&#40;</span><span class="kw4">void</span><span class="sy2">*</span> thrown_exception, std<span class="sy4">::</span><span class="me2">type_info</span><span class="sy2">*</span> tinfo, <span class="kw4">bool</span> rethrown<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">char</span><span class="sy2">*</span> demangled <span class="sy1">=</span> abi<span class="sy4">::</span> __cxa_demangle<span class="br0">&#40;</span>tinfo<span class="sy2">-</span><span class="sy1">&gt;</span>name<span class="br0">&#40;</span><span class="br0">&#41;</span>, 0, 0, 0<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">fprintf</span><span class="br0">&#40;</span><span class="kw2">stderr</span>, <span class="st0">&quot;%s exception of type %s<span class="es1">\n</span>&quot;</span>, <span class="br0">&#40;</span>rethrown <span class="sy4">?</span> <span class="st0">&quot;Rethrown&quot;</span> <span class="sy4">:</span> <span class="st0">&quot;Thrown&quot;</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span>demangled <span class="sy4">?</span> demangled <span class="sy4">:</span> tinfo<span class="sy2">-</span><span class="sy1">&gt;</span>name<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>demangled<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">free</span><span class="br0">&#40;</span>demangled<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw4">const</span> abi<span class="sy4">::</span>__class_type_info<span class="sy2">*</span> exc <span class="sy1">=</span> <span class="kw2">dynamic_cast</span><span class="sy1">&lt;</span><span class="kw4">const</span> abi<span class="sy4">::</span>__class_type_info<span class="sy2">*</span><span class="sy1">&gt;</span><span class="br0">&#40;</span><span class="sy3">&amp;</span><span class="kw2">typeid</span><span class="br0">&#40;</span>std<span class="sy4">::</span><span class="me2">exception</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">const</span> abi<span class="sy4">::</span>__class_type_info<span class="sy2">*</span> cti <span class="sy1">=</span> <span class="kw2">dynamic_cast</span><span class="sy1">&lt;</span>abi<span class="sy4">::</span>__class_type_info<span class="sy2">*</span><span class="sy1">&gt;</span><span class="br0">&#40;</span>tinfo<span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>cti <span class="sy3">&amp;&amp;</span> exc<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">exception</span><span class="sy2">*</span> the_exception <span class="sy1">=</span> <span class="kw2">reinterpret_cast</span><span class="sy1">&lt;</span>std<span class="sy4">::</span><span class="me2">exception</span><span class="sy2">*</span><span class="sy1">&gt;</span><span class="br0">&#40;</span>abi<span class="sy4">::</span>__dynamic_cast<span class="br0">&#40;</span>thrown_exception, exc, cti, <span class="sy2">-</span>1<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>the_exception<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">fprintf</span><span class="br0">&#40;</span><span class="kw2">stderr</span>, <span class="st0">&quot;what(): %s<span class="es1">\n</span>&quot;</span>, the_exception<span class="sy2">-</span><span class="sy1">&gt;</span>what<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; get_backtrace<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">fprintf</span><span class="br0">&#40;</span><span class="kw2">stderr</span>, <span class="st0">&quot;<span class="es1">\n</span><span class="es1">\n</span>&quot;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">extern</span> <span class="st0">&quot;C&quot;</span> <span class="kw4">void</span> __cxa_throw<span class="br0">&#40;</span><span class="kw4">void</span><span class="sy2">*</span> thrown_exception, std<span class="sy4">::</span><span class="me2">type_info</span><span class="sy2">*</span> tinfo, <span class="kw4">void</span> <span class="br0">&#40;</span><span class="sy2">*</span>dest<span class="br0">&#41;</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy2">*</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; pthread_mutex_lock<span class="br0">&#40;</span><span class="sy3">&amp;</span>guard<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; handle_exception<span class="br0">&#40;</span>thrown_exception, tinfo, <span class="kw2">false</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; pthread_mutex_unlock<span class="br0">&#40;</span><span class="sy3">&amp;</span>guard<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>orig_cxa_throw<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; orig_cxa_throw<span class="br0">&#40;</span>thrown_exception, tinfo, dest<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">terminate</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">extern</span> <span class="st0">&quot;C&quot;</span> <span class="kw4">void</span> __cxa_rethrow<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; pthread_mutex_lock<span class="br0">&#40;</span><span class="sy3">&amp;</span>guard<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; __cxa_eh_globals<span class="sy2">*</span> g <span class="sy1">=</span> __cxa_get_globals<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>g <span class="sy3">&amp;&amp;</span> g<span class="sy2">-</span><span class="sy1">&gt;</span>caughtExceptions<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">void</span><span class="sy2">*</span> thrown_exception <span class="sy1">=</span> <span class="kw2">reinterpret_cast</span><span class="sy1">&lt;</span>uint8_t<span class="sy2">*</span><span class="sy1">&gt;</span><span class="br0">&#40;</span>g<span class="sy2">-</span><span class="sy1">&gt;</span>caughtExceptions<span class="br0">&#41;</span> <span class="sy2">+</span> <span class="kw3">sizeof</span><span class="br0">&#40;</span><span class="kw4">struct</span> __cxa_exception<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; handle_exception<span class="br0">&#40;</span>thrown_exception, g<span class="sy2">-</span><span class="sy1">&gt;</span>caughtExceptions<span class="sy2">-</span><span class="sy1">&gt;</span>exceptionType, <span class="kw2">true</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; pthread_mutex_unlock<span class="br0">&#40;</span><span class="sy3">&amp;</span>guard<span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>orig_cxa_rethrow<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; orig_cxa_rethrow<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">terminate</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="co1">// Инициализация переменных. Можно сделать это и в обработчике, но так безопаснее</span><br />
<span class="kw4">static</span> <span class="kw4">void</span> initialize<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; orig_cxa_throw &nbsp; <span class="sy1">=</span> <span class="kw2">reinterpret_cast</span><span class="sy1">&lt;</span>cxa_throw_type<span class="sy1">&gt;</span><span class="br0">&#40;</span>dlsym<span class="br0">&#40;</span>RTLD_NEXT, <span class="st0">&quot;__cxa_throw&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; orig_cxa_rethrow <span class="sy1">=</span> <span class="kw2">reinterpret_cast</span><span class="sy1">&lt;</span>cxa_rethrow_type<span class="sy1">&gt;</span><span class="br0">&#40;</span>dlsym<span class="br0">&#40;</span>RTLD_NEXT, <span class="st0">&quot;__cxa_rethrow&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">int</span> main<span class="br0">&#40;</span><span class="kw4">int</span>, <span class="kw4">char</span><span class="sy2">**</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; initialize<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">try</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">try</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">throw</span> std<span class="sy4">::</span><span class="me2">runtime_error</span><span class="br0">&#40;</span><span class="st0">&quot;123&quot;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">catch</span> <span class="br0">&#40;</span><span class="kw4">const</span> std<span class="sy4">::</span><span class="me2">exception</span><span class="sy3">&amp;</span> e<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">printf</span><span class="br0">&#40;</span><span class="st0">&quot;e.what(): %s<span class="es1">\n</span>&quot;</span>, e.<span class="me1">what</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">throw</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw2">catch</span> <span class="br0">&#40;</span><span class="kw4">const</span> std<span class="sy4">::</span><span class="me2">exception</span><span class="sy3">&amp;</span> d<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">printf</span><span class="br0">&#40;</span><span class="st0">&quot;d.what(): %s<span class="es1">\n</span>&quot;</span>, d.<span class="me1">what</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">try</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">throw</span> <span class="nu0">1</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw2">catch</span> <span class="br0">&#40;</span><span class="kw4">int</span> x<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">printf</span><span class="br0">&#40;</span><span class="st0">&quot;%d<span class="es1">\n</span>&quot;</span>, x<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">0</span><span class="sy4">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Пример работы (у меня в оригинале кода нет комментариев, так что номера строк будут отличаться):</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96912">
        <div class="code text" id="p969code12">
$ g++ test.cpp -O2 -g -o test -ldl<br />
$ ./test<br />
Thrown exception of type std::runtime_error<br />
what(): 123<br />
*** BACKTRACE ***<br />
./test[0x401127]<br />
./test(__cxa_throw+0x33)[0x401303]<br />
./test[0x40141f]<br />
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f3c05c2576d]<br />
./test[0x400fa9]<br />
<br />
*** DECODED BACKTRACE ***<br />
/usr/bin/addr2line -pifCa -e `/bin/readlink /proc/4387/exe` 0x401127 0x401303 0x40141f 0x7f3c05c2576d 0x400fa9 1&gt;&amp;2<br />
0x0000000000401127: fprintf at /usr/include/x86_64-linux-gnu/bits/stdio2.h:99<br />
&nbsp;(inlined by) get_backtrace at /home/vladimir/test/test.cpp:73<br />
&nbsp;(inlined by) handle_exception at /home/vladimir/test/test.cpp:114<br />
0x0000000000401303: __cxa_throw at /home/vladimir/test/test.cpp:122<br />
0x000000000040141f: main at /home/vladimir/test/test.cpp:167<br />
0x00007f3c05c2576d: ??<br />
??:0<br />
0x0000000000400fa9: _start at ??:0<br />
<br />
<br />
e.what(): 123<br />
Rethrown exception of type std::runtime_error<br />
what(): 123<br />
*** BACKTRACE ***<br />
./test[0x401127]<br />
./test(__cxa_rethrow+0x31)[0x401371]<br />
./test[0x4014de]<br />
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f3c05c2576d]<br />
./test[0x400fa9]<br />
<br />
*** DECODED BACKTRACE ***<br />
/usr/bin/addr2line -pifCa -e `/bin/readlink /proc/4387/exe` 0x401127 0x401371 0x4014de 0x7f3c05c2576d 0x400fa9 1&gt;&amp;2<br />
0x0000000000401127: fprintf at /usr/include/x86_64-linux-gnu/bits/stdio2.h:99<br />
&nbsp;(inlined by) get_backtrace at /home/vladimir/test/test.cpp:73<br />
&nbsp;(inlined by) handle_exception at /home/vladimir/test/test.cpp:114<br />
0x0000000000401371: __cxa_rethrow at /home/vladimir/test/test.cpp:141<br />
0x00000000004014de: main at /home/vladimir/test/test.cpp:179<br />
0x00007f3c05c2576d: ??<br />
??:0<br />
0x0000000000400fa9: _start at ??:0<br />
<br />
<br />
d.what(): 123<br />
Thrown exception of type int<br />
*** BACKTRACE ***<br />
./test[0x401127]<br />
./test(__cxa_throw+0x33)[0x401303]<br />
./test[0x4014b7]<br />
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f3c05c2576d]<br />
./test[0x400fa9]<br />
<br />
*** DECODED BACKTRACE ***<br />
/usr/bin/addr2line -pifCa -e `/bin/readlink /proc/4387/exe` 0x401127 0x401303 0x4014b7 0x7f3c05c2576d 0x400fa9 1&gt;&amp;2<br />
0x0000000000401127: fprintf at /usr/include/x86_64-linux-gnu/bits/stdio2.h:99<br />
&nbsp;(inlined by) get_backtrace at /home/vladimir/test/test.cpp:73<br />
&nbsp;(inlined by) handle_exception at /home/vladimir/test/test.cpp:114<br />
0x0000000000401303: __cxa_throw at /home/vladimir/test/test.cpp:122<br />
0x00000000004014b7: main at /home/vladimir/test/test.cpp:167<br />
0x00007f3c05c2576d: ??<br />
??:0<br />
0x0000000000400fa9: _start at ??:0<br />
<br />
<br />
1
        </div>
    </div>
</div>

<p>Для proof of concept очень даже неплохо.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/969-track-uncaught-exceptions/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/c-cpp/969-track-uncaught-exceptions/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Совмещение различных конфигураций сборок при использовании qmake</title>
		<link>http://blog.sjinks.pro/c-cpp/qt/967-qmake-combine-different-build-types/</link>
		<comments>http://blog.sjinks.pro/c-cpp/qt/967-qmake-combine-different-build-types/#comments</comments>
		<pubDate>Sat, 28 Apr 2012 23:45:14 +0000</pubDate>
		<dc:creator>Wandering Soul</dc:creator>
				<category><![CDATA[Qt]]></category>
		<category><![CDATA[qmake]]></category>
		<category><![CDATA[ошибка]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=967</guid>
		<description><![CDATA[Недокументированные костыли qmake В продолжение темы одновременной сборки взаимно несовместимых конфигураций. В предыдущей записи было показано, что qmake позволяет собирать одновременно взаимно несовместимые конфигурации, как-то: отладочная и релиз-версия приложения, статическая и динамическая версия библиотеки. Тем не менее, без лишних телодвижений совместить несколько конфигураций сборок (например, отладочная и релиз-версия статической и динамической библиотеки) проблематично. В частности, [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/qt/967-qmake-combine-different-build-types/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Недокументированные костыли <a href="http://blog.sjinks.pro/tag/qmake/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  qmake">qmake</a></em></h2>
<p>В продолжение темы <a href="http://blog.sjinks.pro/c-cpp/qt/966-qmake-static-shared-library/" title="Одновременная сборка статической и динамической библиотеки с qmake">одновременной сборки взаимно несовместимых конфигураций</a>.</p>
<p>В предыдущей записи было показано, что qmake позволяет собирать одновременно взаимно несовместимые конфигурации, как-то: отладочная и релиз-версия приложения, статическая и динамическая версия библиотеки.</p>
<p>Тем не менее, без лишних телодвижений совместить несколько конфигураций сборок (например, отладочная и релиз-версия статической и динамической библиотеки) проблематично.<span id="more-967"></span></p>
<p>В частности, если задать такую конфигурацию:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96716">
        <div class="code qmake" id="p967code16">
CONFIG += static_and_shared debug_and_release build_all
        </div>
    </div>
</div>

<p>qmake сгенерирует только каталоги <code>debug</code> и <code>release</code>, хотя и создаст все пять <code>Makefile</code>:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96717">
        <div class="code bash" id="p967code17">
$ <span class="kw2">ls</span> <span class="re5">-1</span><br />
debug<br />
Makefile<br />
Makefile.SharedDebug<br />
Makefile.SharedRelease<br />
Makefile.StaticDebug<br />
Makefile.StaticRelease<br />
release
        </div>
    </div>
</div>

<p>Выполнив make, видим, что с таким подходом результат может быть весьма непредсказуемым: в моём случае сначала собиралась цель <code>shared-release</code>, затем <code>shared-debug</code>, затем из объектных файлов, собранных для цели <code>shared-release</code>, собиралась статическая библиотека для цели <code>static-release</code>; аналогично со <code>static-debug</code>.</p>
<p>Плохо это по крайней мере по двум причинам:</p>
<ol>
<li>Ломается параллельная сборка: при сборке библиотеки может случиться ситуация, когда смешиваются по-разному скомпилированные объектные файлы (например, с и без <abbr title="Position Independent Code">PIC</abbr>); в лучшем случае получим предупреждение от компоновщика (что-нибудь загадочное вида <code>error: /tmp/ccdxxjfh.ltrans1.ltrans.o: requires dynamic R_X86_64_PC32 reloc against 'vtable for ClassName' which may overflow at runtime; recompile with -fPIC</code>), в худшем — столкнёмся с весьма интересными ошибками</li>
<li>Однозадачная сборка зависит от порядка сборки целей: например, если собирать сначала статическую цель, затем — динамическую, и если при этом статическая библиотека явно не экспортирует функции (например, собирается с <code>-fvisibility=hidden</code>), то динамическая цель, собранная из файлов для статической цели, может оказаться неработоспособной.</li>
</ol>
<p>Причина, по которой это происходит, лежит в недрах qmake: всё дело в том, что сборка несовместимых конфигураций является неким костылём. Костыльность эта заключается именно в обработке целей:</p>
<ul>
<li><strong>начальная конфигурация:</strong> <code>static_and_shared debug_and_release build_all</code></li>
<li>изначально имеем пустую переменную <code>OBJECTS_DIR</code></li>
<li>qmake начинает с релизной сборки из <code>debug_and_release</code></li>
<li>обработка первой цели (<code>Release</code>) поместит в <code>OBJECTS_DIR</code> значение <code>release</code></li>
<li>qmake обрабатывает «вложенную» сборку: <code>shared</code> из <code>static_and_shared</code></li>
<li><strong>костыль:</strong> qmake предполагает, что предыдущей сборки либо не было (<code>OBJECTS_DIR</code> и компания пусты — в этом случае каталог для временных файлов будет совпадать с именем сборки, в нашем случае это <code>shared</code>), либо конфигурация предыдущей сборки была «антиподом» текущей (то есть <code>static</code> в данном случае) — тогда в <code>OBJECTS_DIR</code> и сопуствующих переменных <code>static</code> заменяется на <code>shared</code>. Но проблема тут в том, что предыдущая конфигурация была <code>release</code>, а не <code>static</code>; как следствие, замена не получится, каталогом для временных файлов останется <code>release</code></li>
<li>затем обрабатывается конфигурация <code>debug</code>; в <code>OBJECTS_DIR</code> <code>release</code> успешно заменяется на <code>debug</code></li>
<li>затем обрабатывается подконфигурация shared; <code>OBJECTS_DIR</code> остаётся без изменений</li>
<li><strong>краткий итог:</strong> конфигурация <code>release/shared</code> собрана в <code>release</code>, <code>debug/shared</code> — в <code>debug</code></li>
<li>затем обрабатывается конфигурация <code>static</code>; <code>OBJECTS_DIR</code> опять остаётся без изменений (<code>debug</code>)</li>
<li>обрабатывается подконфигурация <code>release</code>; в <code>OBJECTS_DIR</code> <code>debug</code> успешно заменяется на <code>release</code>; в результате <code>static/release</code> будет собираться в <code>release</code>, где собиралась конфигурация <code>release/shared</code></li>
<li>совершенно аналогично <code>static/debug</code> будет собираться в <code>debug</code>, где собиралась конфигурация <code>debug/shared</code></li>
</ul>
<p>Временные файлы (в зависимости от их типа) помещаются в каталоги, указанные переменными <code>OBJECTS_DIR</code>, <code>MOC_DIR</code> и <code>RCC_DIR</code>.</p>
<p>Для того, чтобы сборка прошла успешно, нужно устанавливать их значения самостоятельно.</p>
<p>У меня получилось так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96718">
        <div class="code qmake" id="p967code18">
CONFIG += static_and_shared debug_and_release build_all<br />
<br />
debug: TARGET = $$join(TARGET,,,_debug)<br />
<br />
StaticDebug: &nbsp; OBJECTS_DIR = StaticDebug<br />
SharedDebug: &nbsp; OBJECTS_DIR = SharedDebug<br />
StaticRelease: OBJECTS_DIR = StaticRelease<br />
SharedRelease: OBJECTS_DIR = SharedRelease<br />
<br />
MOC_DIR = $$OBJECTS_DIR<br />
RCC_DIR = $$OBJECTS_DIR
        </div>
    </div>
</div>

<p>Если отладочная и релизная версия должны размещаться в разных каталогах, нужно также изменять переменную <code>DESTDIR</code>.</p>
<p>В общем, happy hackin&#8217;!</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/qt/967-qmake-combine-different-build-types/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/c-cpp/qt/967-qmake-combine-different-build-types/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Одновременная сборка статической и динамической библиотеки с qmake</title>
		<link>http://blog.sjinks.pro/c-cpp/qt/966-qmake-static-shared-library/</link>
		<comments>http://blog.sjinks.pro/c-cpp/qt/966-qmake-static-shared-library/#comments</comments>
		<pubDate>Sun, 22 Apr 2012 12:46:07 +0000</pubDate>
		<dc:creator>Wandering Soul</dc:creator>
				<category><![CDATA[Qt]]></category>
		<category><![CDATA[qmake]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=966</guid>
		<description><![CDATA[Недокументированные возможности qmake Задача: заставить qmake генерировать статическую и динамическую библиотеку при использовании шаблона сборки lib. Решение: хотя считается, что без костылей такая возможность не реализуется, на самом деле это не так: поддержка одновременной сборки статической и динамической версии библиотеки присутствует по крайней мере со времён Qt 4.5. Всё дело в волшебных prf-файлах. Цитируя официальную [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/qt/966-qmake-static-shared-library/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Недокументированные возможности <a href="http://blog.sjinks.pro/tag/qmake/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  qmake">qmake</a></em></h2>
<p><strong>Задача:</strong> заставить qmake генерировать статическую и динамическую библиотеку при использовании шаблона сборки <code>lib</code>.<span id="more-966"></span></p>
<p>Решение: хотя считается, что без костылей такая возможность не реализуется, на самом деле это не так: поддержка одновременной сборки статической и динамической версии библиотеки присутствует по крайней мере со времён <a href="http://blog.sjinks.pro/tag/qt/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Qt">Qt</a> 4.5.</p>
<p>Всё дело в волшебных prf-файлах. Цитируя официальную документацию,</p>
<blockquote>qmake lets you create your own features that can be included in project files by adding their names to the list of values specified by the CONFIG variable. Features are collections of custom functions and definitions in .prf files that can reside in one of many standard directories.</blockquote>
<p>Если посмотреть каталог <code>mkspec/features</code> в Qt (например, в Ubuntu/Debian это <code>/usr/share/qt4/mkspecs/features/</code>), можно увидеть файл <code>static_and_shared.prf</code>, отвечающий за одновременную сборку статической и динамической версии библиотек.</p>
<p>Использовать это можно так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96621">
        <div class="code gmake" id="p966code21">
TEMPLATE &nbsp;= lib<br />
CONFIG &nbsp; += static_and_shared create_prl build_all
        </div>
    </div>
</div>

<p><code>TEMPLATE = lib</code> задаёт шаблон сборки (библиотека), <code>static_and_shared</code> задаёт режим сборки, <code>create_prl</code> (используется при сборке статической библиотеки) включает режим отслеживания зависимостей библиотеки, <code>build_all</code> указывает, что собирать нужно обе версии.</p>
<p>Из параметров <code>CONFIG</code> недокументированным является только <code>static_and_shared</code>.</p>
<p>Задать различные опции для статической и динамической сборки можно через функцию <code>CONFIG</code>:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96622">
        <div class="code qmake" id="p966code22">
build_pass: CONFIG(static, static|shared) {<br />
# Опции для статической библиотеки<br />
}<br />
<br />
build_pass: CONFIG(shared, static|shared) {<br />
# Опции для динамической библиотеки<br />
}
        </div>
    </div>
</div>

<p>На закуску еще две полезных опции для использования в <code>CONFIG</code> для <a href="http://blog.sjinks.pro/tag/linux/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Linux">Linux</a>/UNIX:</p>
<ol>
<li><code>hide_symbols</code>: установка видимости символов по умолчанию в hidden. Для чего нужно, читаем <a href="http://gcc.gnu.org/wiki/Visibility">здесь</a>.</li>
<li><code>bsymbolic_functions</code>: привязка ссылок на глобальные функции к определениям этих функций в самой библиотеке (что не позволит привязывать ссылки из библиотеки на свои функции к функциям, экспортируемым из другой библиотеки)</li>
</ol>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/qt/966-qmake-static-shared-library/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/c-cpp/qt/966-qmake-static-shared-library/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Отслеживание источника исключения в Qt</title>
		<link>http://blog.sjinks.pro/c-cpp/qt/964-exception-source-qt/</link>
		<comments>http://blog.sjinks.pro/c-cpp/qt/964-exception-source-qt/#comments</comments>
		<pubDate>Fri, 13 Apr 2012 21:05:31 +0000</pubDate>
		<dc:creator>Wandering Soul</dc:creator>
				<category><![CDATA[Qt]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[gcc]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=964</guid>
		<description><![CDATA[Получение трассы вызовов к источнику исключений в Qt Если приложение (или сама библиотека Qt) бросает исключение, которое не обрабатывается приложением, исключение попадает в цикл обработки событий Qt (известный как event loop), который выводит сообщение наподобие: Qt has caught an exception thrown from an event handler. Throwing exceptions from an event handler is not supported in [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/qt/964-exception-source-qt/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Получение трассы вызовов к источнику исключений в <a href="http://blog.sjinks.pro/tag/qt/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Qt">Qt</a></em></h2>
<p>Если приложение (или сама библиотека Qt) бросает исключение, которое не обрабатывается приложением, исключение попадает в цикл обработки событий Qt (известный как event loop), который выводит сообщение наподобие:</p>
<p><strong>Qt has caught an exception thrown from an event handler. Throwing<br />
exceptions from an event handler is not supported in Qt. You must<br />
reimplement QApplication::notify() and catch all exceptions there.<br />
</strong></p>
<p>При использовании <code>libstdc++</code> может быть выдана дополнительная диагностика:</p>
<p><strong>terminate called after throwing an instance of &#8216;std::bad_alloc&#8217;<br />
what(): std::bad_alloc</strong><br />
<span id="more-964"></span></p>
<p>Получение стека вызовов из обработчика не пойманных исключений (<code>std::set_terminate</code>) здесь не поможет: трасса приведёт к тому месту, откуда исключение было брошено повторно — то есть в цикл обработки событий Qt.</p>
<p>В случае использования <a href="http://blog.sjinks.pro/tag/gcc/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  gcc">gcc</a> проблему можно решить, поставив в отладчике точку прерывания на функцию <code>__cxa_throw</code>.</p>
<p>Например, в случае с gdb:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96424">
        <div class="code text" id="p964code24">
$ gdb buggy_app <br />
GNU gdb (Ubuntu/Linaro 7.4-2012.02-0ubuntu2) 7.4-2012.02<br />
Copyright (C) 2012 Free Software Foundation, Inc.<br />
License GPLv3+: GNU GPL version 3 or later &lt;http://gnu.org/licenses/gpl.html&gt;<br />
This is free software: you are free to change and redistribute it.<br />
There is NO WARRANTY, to the extent permitted by law. &nbsp;Type &quot;show copying&quot;<br />
and &quot;show warranty&quot; for details.<br />
This GDB was configured as &quot;x86_64-linux-gnu&quot;.<br />
For bug reporting instructions, please see:<br />
&lt;http://bugs.launchpad.net/gdb-linaro/&gt;...<br />
Reading symbols from /path/to/buggy_app...done.<br />
(gdb) start<br />
Temporary breakpoint 1 at 0x405f6d: file main.cpp, line 75.<br />
Starting program: /path/to/buggy_app<br />
[Thread debugging using libthread_db enabled]<br />
Using host libthread_db library &quot;/lib/x86_64-linux-gnu/libthread_db.so.1&quot;.<br />
<br />
Temporary breakpoint 1, main (argc=3, argv=0x7fffffffe008) at main.cpp:75<br />
75 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;QCoreApplication a(argc, argv);<br />
(gdb) b __cxa_throw<br />
Breakpoint 2 at 0x7ffff7154910<br />
(gdb) c<br />
Continuing.<br />
<br />
Breakpoint 2, 0x00007ffff7154910 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6<br />
(gdb) bt<br />
#0 &nbsp;0x00007ffff7154910 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6<br />
#1 &nbsp;0x00007ffff762d102 in qBadAlloc () at global/qglobal.cpp:1994<br />
#2 &nbsp;0x00007ffff7fe6e7e in DnsRequestQueuePrivate::_q_resultsReady (this=0x43af90, r=..., id=11771, code=0, ctx=...) at dnsrequestqueue.cpp:83<br />
#3 &nbsp;0x00007ffff7fe7629 in DnsRequestQueue::qt_static_metacall (_o=0x7fffffffded8, _c=QMetaObject::InvokeMetaMethod, _id=1, _a=0x43d130) at debug/moc_dnsrequestqueue.cpp:53<br />
#4 &nbsp;0x00007ffff7750446 in QObject::event (this=0x7fffffffded8, e=&lt;optimized out&gt;) at kernel/qobject.cpp:1195<br />
#5 &nbsp;0x00007ffff7736e9c in QCoreApplication::notifyInternal (this=0x7fffffffdf00, receiver=0x7fffffffded8, event=0x43d310) at kernel/qcoreapplication.cpp:876<br />
...
        </div>
    </div>
</div>

<p>Для экстремалов есть такое решение: <a href="http://zbigg.blogspot.com/2009/03/hijacking-throw.html">Hijacking throw</a></p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/qt/964-exception-source-qt/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/c-cpp/qt/964-exception-source-qt/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Undefined reference на специализацию шаблона статического поля</title>
		<link>http://blog.sjinks.pro/c-cpp/962-undefined-reference-to-static-field-template-initialization/</link>
		<comments>http://blog.sjinks.pro/c-cpp/962-undefined-reference-to-static-field-template-initialization/#comments</comments>
		<pubDate>Sat, 31 Mar 2012 20:24:53 +0000</pubDate>
		<dc:creator>Wandering Soul</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[gcc]]></category>
		<category><![CDATA[ошибка]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=962</guid>
		<description><![CDATA[GCC временами весьма капризен Столкнулся на работе с такой проблемой при написании расширения для QtScript: код вида template&#60;typename T&#62; class EnumWrapper { /* ... */ protected: static QMap&#60;int, QString&#62; m_enum_map; static QString m_class; /* ... */ }; template&#60;&#62; QMap&#60;int, QString&#62; EnumWrapper&#60;QTextStream::RealNumberNotation&#62;::m_enum_map; template&#60;&#62; QString EnumWrapper&#60;QTextStream::RealNumberNotation&#62;::m_class(QLatin1String(&#34;QTextStream&#34;)); class QTextStream_RealNumberNotation : public EnumWrapper&#60;QTextStream::RealNumberNotation&#62; { public: QTextStream_RealNumberNotation(void) { EnumWrapper&#60;QTextStream::RealNumberNotation&#62;::m_enum_map.insert(int(QTextStream::SmartNotation), QLatin1String(&#34;SmartNotation&#34;)); [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/962-undefined-reference-to-static-field-template-initialization/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em><a href="http://blog.sjinks.pro/tag/gcc/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  gcc">GCC</a> временами весьма капризен</em></h2>
<p>Столкнулся на работе с такой проблемой при написании расширения для QtScript: код вида<span id="more-962"></span></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96232">
        <div class="code cpp" id="p962code32">
<span class="kw2">template</span><span class="sy1">&lt;</span><span class="kw2">typename</span> T<span class="sy1">&gt;</span><br />
<span class="kw2">class</span> EnumWrapper <span class="br0">&#123;</span><br />
<span class="coMULTI">/* ... */</span><br />
<br />
<span class="kw2">protected</span><span class="sy4">:</span><br />
&nbsp; &nbsp; <span class="kw4">static</span> QMap<span class="sy1">&lt;</span><span class="kw4">int</span>, QString<span class="sy1">&gt;</span> m_enum_map<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">static</span> QString m_class<span class="sy4">;</span><br />
<span class="coMULTI">/* ... */</span><br />
<span class="br0">&#125;</span><span class="sy4">;</span><br />
<br />
<span class="kw2">template</span><span class="sy1">&lt;&gt;</span> QMap<span class="sy1">&lt;</span><span class="kw4">int</span>, QString<span class="sy1">&gt;</span> EnumWrapper<span class="sy1">&lt;</span>QTextStream<span class="sy4">::</span><span class="me2">RealNumberNotation</span><span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">m_enum_map</span><span class="sy4">;</span><br />
<span class="kw2">template</span><span class="sy1">&lt;&gt;</span> QString EnumWrapper<span class="sy1">&lt;</span>QTextStream<span class="sy4">::</span><span class="me2">RealNumberNotation</span><span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">m_class</span><span class="br0">&#40;</span>QLatin1String<span class="br0">&#40;</span><span class="st0">&quot;QTextStream&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
<span class="kw2">class</span> QTextStream_RealNumberNotation <span class="sy4">:</span> <span class="kw2">public</span> EnumWrapper<span class="sy1">&lt;</span>QTextStream<span class="sy4">::</span><span class="me2">RealNumberNotation</span><span class="sy1">&gt;</span> <span class="br0">&#123;</span><br />
<span class="kw2">public</span><span class="sy4">:</span><br />
&nbsp; &nbsp; QTextStream_RealNumberNotation<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; EnumWrapper<span class="sy1">&lt;</span>QTextStream<span class="sy4">::</span><span class="me2">RealNumberNotation</span><span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">m_enum_map</span>.<span class="me1">insert</span><span class="br0">&#40;</span><span class="kw4">int</span><span class="br0">&#40;</span>QTextStream<span class="sy4">::</span><span class="me2">SmartNotation</span><span class="br0">&#41;</span>, QLatin1String<span class="br0">&#40;</span><span class="st0">&quot;SmartNotation&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; EnumWrapper<span class="sy1">&lt;</span>QTextStream<span class="sy4">::</span><span class="me2">RealNumberNotation</span><span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">m_enum_map</span>.<span class="me1">insert</span><span class="br0">&#40;</span><span class="kw4">int</span><span class="br0">&#40;</span>QTextStream<span class="sy4">::</span><span class="me2">FixedNotation</span><span class="br0">&#41;</span>, QLatin1String<span class="br0">&#40;</span><span class="st0">&quot;FixedNotation&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; EnumWrapper<span class="sy1">&lt;</span>QTextStream<span class="sy4">::</span><span class="me2">RealNumberNotation</span><span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">m_enum_map</span>.<span class="me1">insert</span><span class="br0">&#40;</span><span class="kw4">int</span><span class="br0">&#40;</span>QTextStream<span class="sy4">::</span><span class="me2">ScientificNotation</span><span class="br0">&#41;</span>, QLatin1String<span class="br0">&#40;</span><span class="st0">&quot;ScientificNotation&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><span class="sy4">;</span><br />
<br />
<span class="coMULTI">/* ... */</span><br />
<br />
QTextStream_RealNumberNotation c<span class="sy4">;</span>
        </div>
    </div>
</div>

<p>делает полученную библиотеку незагружаемой.</p>
<p>Методом проб и ошибок было установлено, что всему виной такая декларация:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96233">
        <div class="code cpp" id="p962code33">
<span class="kw2">template</span><span class="sy1">&lt;&gt;</span> QMap<span class="sy1">&lt;</span><span class="kw4">int</span>, QString<span class="sy1">&gt;</span> EnumWrapper<span class="sy1">&lt;</span>QTextStream<span class="sy4">::</span><span class="me2">RealNumberNotation</span><span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">m_enum_map</span><span class="sy4">;</span>
        </div>
    </div>
</div>

<p>Чтобы лучше понять суть проблемы, набросал небольшой test case, который не использует сторонних библиотек (мало ли, вдруг <a href="http://blog.sjinks.pro/tag/qt/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Qt">Qt</a> виноват):</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96234">
        <div class="code cpp" id="p962code34">
<span class="co2">#include &lt;map&gt;</span><br />
<span class="co2">#include &lt;utility&gt;</span><br />
<br />
<span class="kw2">template</span><span class="sy1">&lt;</span><span class="kw2">typename</span> T<span class="sy1">&gt;</span><br />
<span class="kw2">class</span> Test <span class="br0">&#123;</span><br />
<span class="kw2">public</span><span class="sy4">:</span><br />
&nbsp; &nbsp; Test<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; m_map.<span class="me1">insert</span><span class="br0">&#40;</span>std<span class="sy4">::</span><span class="me2">make_pair</span><span class="br0">&#40;</span>0, 0<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw4">static</span> std<span class="sy4">::</span><span class="me2">map</span><span class="sy1">&lt;</span><span class="kw4">int</span>, <span class="kw4">int</span><span class="sy1">&gt;</span> m_map<span class="sy4">;</span><br />
<span class="br0">&#125;</span><span class="sy4">;</span><br />
<br />
<span class="kw2">template</span><span class="sy1">&lt;&gt;</span> std<span class="sy4">::</span><span class="me2">map</span><span class="sy1">&lt;</span><span class="kw4">int</span>, <span class="kw4">int</span><span class="sy1">&gt;</span> Test<span class="sy1">&lt;</span><span class="kw4">char</span><span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">m_map</span><span class="sy4">;</span><br />
<br />
<span class="kw4">int</span> main<span class="br0">&#40;</span><span class="kw4">int</span>, <span class="kw4">char</span><span class="sy2">**</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; Test<span class="sy1">&lt;</span><span class="kw4">char</span><span class="sy1">&gt;</span> t<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">0</span><span class="sy4">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>И вот оно, gcc громко ругается:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96235">
        <div class="code text" id="p962code35">
$ g++ test.cpp -o test<br />
/tmp/ccyD9dfl.o:test.cpp:function Test&lt;char&gt;::Test(): error: undefined reference to 'Test&lt;char&gt;::m_map'<br />
collect2: ld returned 1 exit status
        </div>
    </div>
</div>

<p>Компоновщик почему-то в упор отказывается замечать декларацию</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96236">
        <div class="code cpp" id="p962code36">
<span class="kw2">template</span><span class="sy1">&lt;&gt;</span> std<span class="sy4">::</span><span class="me2">map</span><span class="sy1">&lt;</span><span class="kw4">int</span>, <span class="kw4">int</span><span class="sy1">&gt;</span> Test<span class="sy1">&lt;</span><span class="kw4">char</span><span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">m_map</span><span class="sy4">;</span>
        </div>
    </div>
</div>

<p>В VC9 такое не проявляется.</p>
<p>На решение натолкнула следующая за QMap декларация:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96237">
        <div class="code cpp" id="p962code37">
<span class="kw2">template</span><span class="sy1">&lt;&gt;</span> QString EnumWrapper<span class="sy1">&lt;</span>QTextStream<span class="sy4">::</span><span class="me2">RealNumberNotation</span><span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">m_class</span><span class="br0">&#40;</span>QLatin1String<span class="br0">&#40;</span><span class="st0">&quot;QTextStream&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span>
        </div>
    </div>
</div>

<p>На неё компоновщик не ругается. А вся разница — в явном вызове конструктора. Поэтому, если сделать как-то так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p96238">
        <div class="code cpp" id="p962code38">
<span class="kw2">template</span><span class="sy1">&lt;&gt;</span> std<span class="sy4">::</span><span class="me2">map</span><span class="sy1">&lt;</span><span class="kw4">int</span>, <span class="kw4">int</span><span class="sy1">&gt;</span> Test<span class="sy1">&lt;</span><span class="kw4">char</span><span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">m_map</span> <span class="sy1">=</span> std<span class="sy4">::</span><span class="me2">map</span><span class="sy1">&lt;</span><span class="kw4">int</span>, <span class="kw4">int</span><span class="sy1">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
<span class="co1">// Для исходного случая:</span><br />
<br />
<span class="kw2">template</span><span class="sy1">&lt;&gt;</span> QMap<span class="sy1">&lt;</span><span class="kw4">int</span>, QString<span class="sy1">&gt;</span> EnumWrapper<span class="sy1">&lt;</span>QTextStream<span class="sy4">::</span><span class="me2">RealNumberNotation</span><span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">m_enum_map</span> <span class="sy1">=</span> QMap<span class="sy1">&lt;</span><span class="kw4">int</span>, QString<span class="sy1">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span>
        </div>
    </div>
</div>

<p>то компоновщик перестаёт ругаться.</p>
<p>Шаблонная магия и костылестроение.</p>
<p>Может, кому-то пригодится.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/962-undefined-reference-to-static-field-template-initialization/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/c-cpp/962-undefined-reference-to-static-field-template-initialization/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Qt, libfcgi и многопоточность</title>
		<link>http://blog.sjinks.pro/c-cpp/qt/956-qt-libfcgi-multithreading/</link>
		<comments>http://blog.sjinks.pro/c-cpp/qt/956-qt-libfcgi-multithreading/#comments</comments>
		<pubDate>Sun, 08 Jan 2012 17:31:00 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[Qt]]></category>
		<category><![CDATA[FastCGI]]></category>
		<category><![CDATA[потоки]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=956</guid>
		<description><![CDATA[Предотвращение блокирования событий при использовании libfcgi в многопоточном режиме Для создания приложений FastCGI на C/C++ есть библиотека libfcgi. Не буду вдаваться в дискуссию, зачем нужны приложения FastCGI на C/C++/подставить нужный язык, когда Python/PHP/Perl/подставить нужное гораздо удобнее. Отмечу лишь, что по работе понадобилось написать FastCGI-приложение на Qt (в основном из-за наличия нескольких высокопроизводительных библиотек, написанных на [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/qt/956-qt-libfcgi-multithreading/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Предотвращение блокирования событий при использовании libfcgi в многопоточном режиме</em></h2>
<p>Для создания приложений <a href="http://blog.sjinks.pro/tag/fastcgi/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  FastCGI">FastCGI</a> на <a href="http://blog.sjinks.pro/tag/cpp/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  C/C++">C/C++</a> есть библиотека <a href="http://www.fastcgi.com/devkit/doc/overview.html">libfcgi</a>. Не буду вдаваться в дискуссию, зачем нужны приложения FastCGI на C/C++/подставить нужный язык, когда Python/PHP/Perl/подставить нужное гораздо удобнее. Отмечу лишь, что по работе понадобилось написать FastCGI-приложение на <a href="http://blog.sjinks.pro/tag/qt/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Qt">Qt</a> (в основном из-за наличия нескольких высокопроизводительных библиотек, написанных на <a href="http://blog.sjinks.pro/tag/qt/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Qt">Qt</a>, но не суть).</p>
<p>Строго говоря, libfcgi, хотя и является официальной библиотекой от создателей протокола, не лучший вариант для поддержки FastCGI — API, предоставляемое библиотекой, сильно ограничено (в плане функциональности) и недостаточно гибко.<span id="more-956"></span></p>
<p>Грубо говоря, приложение, использующее libfcgi, может работать в двух режимах:</p>
<ol>
<li>Последовательная обработка запросов: приложение получило запрос, обработало его, отправило результат, получило следующий запрос. Схема хороша, если обработка запроса тривиальна и/или не занимает много времени. Скорее всего, под большой нагрузкой масштабируется плохо, ибо чем длиннее очередь запросов, тем дольши придётся ждать клиенту.</li>
<li><a href="http://www.fastcgi.com/devkit/examples/threaded.c">Многопоточная</a> обработка запросов: приложение создаёт определённое количество потоков, каждый из которых будет обрабатывать свой запрос. При средних нагрузках эта схема работает лучше (если один поток занят, свободный поток займётся выполнением запроса). Но в предельном случае (когда все <a href="http://blog.sjinks.pro/tag/threads/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  потоки">потоки</a> заняты) имеем те же проблемы, что и в первом варианте. Схему можно немного изменить, создавая <a href="http://blog.sjinks.pro/tag/threads/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  потоки">потоки</a> по мере необходимости, но всё равно плодить <a href="http://blog.sjinks.pro/tag/threads/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  потоки">потоки</a> до бесконечности нельзя.</li>
</ol>
<p>Использование потоков не всегда уместно/хорошо: многопоточные программы, как правило, сложнее для разработки и отладки; кроме того, потоки потребляют системные ресурсы (например, память для стека) и при большом количестве потоков эти издержки могут быть существенными (например, для <a href="http://blog.sjinks.pro/tag/linux/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Linux">Linux</a>/IA-32 размер стека для потока по умолчанию составляет 2 мегабайта).</p>
<p>К сожалению, при использовании libfcgi отказаться от потоков очень трудно — дело в том, что библиотека использует блокирующие операции при работе с сокетами.</p>
<p>В общем случае алгоритм работы с libfcgi следующий:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p95643">
        <div class="code c" id="p956code43">
<span class="coMULTI">/* Инициализация */</span><br />
FCGX_Init<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="kw4">int</span> socket <span class="sy0">=</span> FCGX_OpenSocket<span class="br0">&#40;</span><span class="st0">&quot;:9001&quot;</span><span class="sy0">,</span> 256<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="coMULTI">/* ... */</span><br />
<br />
<span class="co1">// Собственно работа</span><br />
<span class="kw1">while</span> <span class="br0">&#40;</span><span class="kw2">true</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; FCGX_Request<span class="sy0">*</span> req <span class="sy0">=</span> new FCGX_Request<span class="sy0">;</span><br />
&nbsp; &nbsp; FCGX_InitRequest<span class="br0">&#40;</span>req<span class="sy0">,</span> socket<span class="sy0">,</span> 0<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw4">int</span> rc <span class="sy0">=</span> FCGX_Accept_r<span class="br0">&#40;</span>req<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>rc <span class="sy0">&gt;=</span> <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="coMULTI">/* Здесь создаём и запускаем поток, отвечающий за обработку запроса */</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>В случае с Qt и использованием рабочего цикла внутри основной программы имеется неприятный подводный камень: из-за того, что <code>FCGX_Accept_r()</code> использует блокирующие вызовы при работе с сокетом, основная программа может очень долго не увидеть сообщения, посылаемые, например, потоком.</p>
<p>Поэтому перед вызовом <code>FCGX_Accept_r()</code> имеет смысл проверять, имеются ли запросы на соединение.<br />
Решение в лоб:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p95644">
        <div class="code cpp" id="p956code44">
<span class="co2">#include &lt;QtCore/QCoreApplication&gt;</span><br />
<span class="co2">#include &lt;sys/select.h&gt;</span><br />
<br />
<span class="coMULTI">/* ... */</span><br />
<br />
<span class="kw4">int</span> rc<span class="sy4">;</span><br />
<span class="kw1">do</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; QCoreApplication<span class="sy4">::</span><span class="me2">processEvents</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">struct</span> timeval tv <span class="sy1">=</span> <span class="br0">&#123;</span> 0, 500 <span class="br0">&#125;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; fd_set r<span class="sy4">;</span><br />
&nbsp; &nbsp; FD_ZERO<span class="br0">&#40;</span><span class="sy3">&amp;</span>r<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; FD_SET<span class="br0">&#40;</span>socket, <span class="sy3">&amp;</span>r<span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; rc <span class="sy1">=</span> <span class="sy4">::</span><span class="me2">select</span><span class="br0">&#40;</span>socket<span class="sy2">+</span>1, <span class="sy3">&amp;</span>r, 0, 0, <span class="sy3">&amp;</span>tv<span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="br0">&#125;</span> <span class="kw1">while</span> <span class="br0">&#40;</span><span class="sy3">!</span>rc<span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
FCGX_Request<span class="sy2">*</span> req <span class="sy1">=</span> <span class="kw3">new</span> FCGX_Request<span class="sy4">;</span><br />
FCGX_InitRequest<span class="br0">&#40;</span>req, socket, 0<span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="kw4">int</span> sock <span class="sy1">=</span> FCGX_Accept_r<span class="br0">&#40;</span>req<span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="coMULTI">/* ... */</span>
        </div>
    </div>
</div>

<p>Но более корректно будет использовать <code>QSocketNotifier</code>:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p95645">
        <div class="code cpp-qt" id="p956code45">
<span class="co1">// core.h</span><br />
<span class="co2">#include &lt;QtCore/QObject&gt;</span><br />
<br />
<span class="kw2">class</span> QSocketNotifier<span class="sy0">;</span><br />
<br />
<span class="kw2">class</span> Core <span class="sy0">:</span> <span class="kw2">public</span> <span class="kw5">QObject</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">Q_OBJECT</span><br />
<span class="kw2">public</span><span class="sy0">:</span><br />
&nbsp; &nbsp; <span class="kw2">explicit</span> Core<span class="br0">&#40;</span><span class="kw5">QObject</span> <span class="sy0">*</span>parent <span class="sy0">=</span> 0<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">void</span> run<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="kw2">private</span><span class="sy0">:</span><br />
&nbsp; &nbsp; <span class="kw5">QSocketNotifier</span><span class="sy0">*</span> m_notifier<span class="sy0">;</span><br />
<br />
<span class="kw2">private</span> <span class="kw2">slots</span><span class="sy0">:</span><br />
&nbsp; &nbsp; <span class="kw4">void</span> connectionPending<span class="br0">&#40;</span><span class="kw4">int</span> socket<span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><span class="sy0">;</span><br />
<br />
<span class="co1">// core.cpp</span><br />
<br />
Core<span class="sy0">::</span><span class="me2">Core</span><span class="br0">&#40;</span><span class="kw5">QObject</span> <span class="sy0">*</span>parent<span class="br0">&#41;</span> <span class="sy0">:</span> <span class="kw5">QObject</span><span class="br0">&#40;</span>parent<span class="br0">&#41;</span><span class="sy0">,</span> m_notifier<span class="br0">&#40;</span>0<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; FCGX_Init<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">int</span> sock <span class="sy0">=</span> FCGX_OpenSocket<span class="br0">&#40;</span><span class="st0">&quot;:9001&quot;</span><span class="sy0">,</span> 256<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; this<span class="sy0">-&gt;</span><span class="me3">m_notifier</span> <span class="sy0">=</span> <span class="kw1">new</span> <span class="kw5">QSocketNotifier</span><span class="br0">&#40;</span>sock<span class="sy0">,</span> <span class="kw5">QSocketNotifier</span><span class="sy0">::</span><span class="me2">Read</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw5">QObject</span><span class="sy0">::</span><span class="kw2">connect</span><span class="br0">&#40;</span>this<span class="sy0">-&gt;</span><span class="me3">m_notifier</span><span class="sy0">,</span> SIGNAL<span class="br0">&#40;</span>activated<span class="br0">&#40;</span><span class="kw4">int</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="kw1">this</span><span class="sy0">,</span> SLOT<span class="br0">&#40;</span>connectionPending<span class="br0">&#40;</span><span class="kw4">int</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> Core<span class="sy0">::</span><span class="me2">connectionPending</span><span class="br0">&#40;</span><span class="kw4">int</span> socket<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw5">QSocketNotifier</span><span class="sy0">*</span> notifier <span class="sy0">=</span> qobject_cast<span class="sy0">&lt;</span><span class="kw5">QSocketNotifier</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>this<span class="sy0">-&gt;</span><span class="me3">sender</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; Q_CHECK_PTR<span class="br0">&#40;</span>notifier<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; notifier<span class="sy0">-&gt;</span><span class="me3">setEnabled</span><span class="br0">&#40;</span><span class="kw2">false</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; FCGX_Request<span class="sy0">*</span> req <span class="sy0">=</span> <span class="kw1">new</span> FCGX_Request<span class="sy0">;</span><br />
&nbsp; &nbsp; FCGX_InitRequest<span class="br0">&#40;</span>req<span class="sy0">,</span> socket<span class="sy0">,</span> 0<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">int</span> s <span class="sy0">=</span> FCGX_Accept_r<span class="br0">&#40;</span>req<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>s <span class="sy0">&gt;=</span> <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="coMULTI">/* Здесь создаём и запускаем поток */</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; notifier<span class="sy0">-&gt;</span><span class="me3">setEnabled</span><span class="br0">&#40;</span><span class="kw2">true</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>В качестве альтернативы созданию потоков можно предложить использовать очередь запросов.</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p95646">
        <div class="code cpp" id="p956code46">
<span class="co2">#include &lt;QtCore/QMutex&gt;</span><br />
<span class="co2">#include &lt;QtCore/QMutexLocker&gt;</span><br />
<span class="co2">#include &lt;QtCore/QQueue&gt;</span><br />
<span class="co2">#include &lt;QtCore/QWaitCondition&gt;</span><br />
<br />
<span class="kw2">class</span> Queue <span class="br0">&#123;</span><br />
<span class="kw2">public</span><span class="sy4">:</span><br />
&nbsp; &nbsp; <span class="kw4">void</span> addToQueue<span class="br0">&#40;</span>FCGX_Request<span class="sy2">*</span> r, <span class="kw4">bool</span> broadcast <span class="sy1">=</span> <span class="kw2">false</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; QMutexLocker locker<span class="br0">&#40;</span><span class="sy3">&amp;</span>this<span class="sy2">-</span><span class="sy1">&gt;</span>mx<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; this<span class="sy2">-</span><span class="sy1">&gt;</span>queue.<span class="me1">enqueue</span><span class="br0">&#40;</span>r<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>broadcast<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this<span class="sy2">-</span><span class="sy1">&gt;</span>cv.<span class="me1">wakeAll</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this<span class="sy2">-</span><span class="sy1">&gt;</span>cv.<span class="me1">wakeOne</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; FCGX_Request<span class="sy2">*</span> getFromQueue<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; this<span class="sy2">-</span><span class="sy1">&gt;</span>mx.<span class="me1">lock</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span>this<span class="sy2">-</span><span class="sy1">&gt;</span>queue.<span class="me1">isEmpty</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this<span class="sy2">-</span><span class="sy1">&gt;</span>cv.<span class="me1">wait</span><span class="br0">&#40;</span><span class="sy3">&amp;</span>this<span class="sy2">-</span><span class="sy1">&gt;</span>mx<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; FCGX_Request<span class="sy2">*</span> result <span class="sy1">=</span> this<span class="sy2">-</span><span class="sy1">&gt;</span>queue.<span class="me1">dequeue</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; this<span class="sy2">-</span><span class="sy1">&gt;</span>mx.<span class="me1">unlock</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> result<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="kw2">private</span><span class="sy4">:</span><br />
&nbsp; &nbsp; QMutex mx<span class="sy4">;</span><br />
&nbsp; &nbsp; QWaitCondition cv<span class="sy4">;</span><br />
&nbsp; &nbsp; QQueue<span class="sy1">&lt;</span>FCGX_Request<span class="sy2">*</span><span class="sy1">&gt;</span> queue<span class="sy4">;</span><br />
<span class="br0">&#125;</span><span class="sy4">;</span>
        </div>
    </div>
</div>

<p>Но это уже совсем другая история.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/qt/956-qt-libfcgi-multithreading/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/c-cpp/qt/956-qt-libfcgi-multithreading/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>HTML Parser для Qt</title>
		<link>http://blog.sjinks.pro/c-cpp/qt/942-html-parser-qt/</link>
		<comments>http://blog.sjinks.pro/c-cpp/qt/942-html-parser-qt/#comments</comments>
		<pubDate>Wed, 07 Sep 2011 08:03:07 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[Qt]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=942</guid>
		<description><![CDATA[Использование libxml2 для разбора документов HTML в Qt XML — это, конечно, хорошо, но очень часто требуется разбирать документы HTML, которые могут и не быть валидными. В Qt есть множество классов для работы с XML, но они не подходят для HTML, так как ошибки в HTML для них фатальны. Ниже приведён вариант парсера для HTML, основанный на [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/qt/942-html-parser-qt/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Использование libxml2 для разбора документов <a href="http://blog.sjinks.pro/tag/html/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  HTML">HTML</a> в <a href="http://blog.sjinks.pro/tag/qt/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Qt">Qt</a></em></h2>
<p><a href="http://blog.sjinks.pro/tag/xml/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  XML">XML</a> — это, конечно, хорошо, но очень часто требуется разбирать документы HTML, которые могут и не быть валидными.</p>
<p>В Qt есть множество классов для работы с XML, но они не подходят для HTML, так как ошибки в HTML для них фатальны.</p>
<p>Ниже приведён вариант парсера для HTML, основанный на библиотеке libxml2.<span id="more-942"></span></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p94251">
        <div class="code cpp-qt" id="p942code51">
<span class="co2">#ifndef LIBXML2READER_H</span><br />
<span class="co2">#define LIBXML2READER_H</span><br />
<br />
<span class="co2">#include &lt;QtXml/QXmlReader&gt;</span><br />
<span class="co2">#include &lt;libxml/xmlstring.h&gt;</span><br />
<br />
<span class="kw2">class</span> LibXml2ReaderPrivate<span class="sy0">;</span><br />
<br />
<span class="kw2">class</span> LibXml2Reader <span class="sy0">:</span> <span class="kw2">public</span> <span class="kw5">QXmlReader</span> <span class="br0">&#123;</span><br />
<span class="kw2">public</span><span class="sy0">:</span><br />
&nbsp; &nbsp; LibXml2Reader<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> ~LibXml2Reader<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">bool</span> feature<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QString</span><span class="sy0">&amp;</span> name<span class="sy0">,</span> <span class="kw4">bool</span><span class="sy0">*</span> ok <span class="sy0">=</span> 0<span class="br0">&#41;</span> const<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">void</span> setFeature<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QString</span><span class="sy0">&amp;</span> name<span class="sy0">,</span> <span class="kw4">bool</span> value<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">bool</span> hasFeature<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QString</span><span class="sy0">&amp;</span> name<span class="br0">&#41;</span> const<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">void</span><span class="sy0">*</span> property<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QString</span><span class="sy0">&amp;</span> name<span class="sy0">,</span> <span class="kw4">bool</span><span class="sy0">*</span> ok <span class="sy0">=</span> 0<span class="br0">&#41;</span> const<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">void</span> setProperty<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QString</span><span class="sy0">&amp;</span> name<span class="sy0">,</span> <span class="kw4">void</span><span class="sy0">*</span> value<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">bool</span> hasProperty<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QString</span><span class="sy0">&amp;</span> name<span class="br0">&#41;</span> const<span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">void</span> setEntityResolver<span class="br0">&#40;</span><span class="kw5">QXmlEntityResolver</span><span class="sy0">*</span> handler<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw5">QXmlEntityResolver</span><span class="sy0">*</span> entityResolver<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> const<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">void</span> setDTDHandler<span class="br0">&#40;</span><span class="kw5">QXmlDTDHandler</span><span class="sy0">*</span> handler<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw5">QXmlDTDHandler</span><span class="sy0">*</span> DTDHandler<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> const<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">void</span> setContentHandler<span class="br0">&#40;</span><span class="kw5">QXmlContentHandler</span><span class="sy0">*</span> handler<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw5">QXmlContentHandler</span><span class="sy0">*</span> contentHandler<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> const<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">void</span> setErrorHandler<span class="br0">&#40;</span><span class="kw5">QXmlErrorHandler</span><span class="sy0">*</span> handler<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw5">QXmlErrorHandler</span><span class="sy0">*</span> errorHandler<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> const<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">void</span> setLexicalHandler<span class="br0">&#40;</span><span class="kw5">QXmlLexicalHandler</span><span class="sy0">*</span> handler<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw5">QXmlLexicalHandler</span><span class="sy0">*</span> lexicalHandler<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> const<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">void</span> setDeclHandler<span class="br0">&#40;</span><span class="kw5">QXmlDeclHandler</span><span class="sy0">*</span> handler<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw5">QXmlDeclHandler</span><span class="sy0">*</span> declHandler<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> const<span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">bool</span> parse<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QXmlInputSource</span><span class="sy0">&amp;</span> input<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">bool</span> parse<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QXmlInputSource</span><span class="sy0">*</span> input<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<br />
<span class="kw2">private</span><span class="sy0">:</span><br />
&nbsp; &nbsp; Q_DISABLE_COPY<span class="br0">&#40;</span>LibXml2Reader<span class="br0">&#41;</span><br />
&nbsp; &nbsp; Q_DECLARE_PRIVATE<span class="br0">&#40;</span>LibXml2Reader<span class="br0">&#41;</span><br />
&nbsp; &nbsp; QScopedPointer<span class="sy0">&lt;</span>LibXml2ReaderPrivate<span class="sy0">&gt;</span> d_ptr<span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">friend</span> <span class="kw2">class</span> LibXml2ReaderLocator<span class="sy0">;</span><br />
<span class="br0">&#125;</span><span class="sy0">;</span><br />
<br />
<span class="co2">#endif // LIBXML2READER_H</span>
        </div>
    </div>
</div>

          
<div class="codebox">
    <div class="the_code" style="" id="p94252">
        <div class="code cpp-qt" id="p942code52">
<span class="co2">#include &quot;libxml2reader.h&quot;</span><br />
<span class="co2">#include &lt;cstring&gt;</span><br />
<span class="co2">#include &lt;libxml/tree.h&gt;</span><br />
<span class="co2">#include &lt;libxml/parser.h&gt;</span><br />
<span class="co2">#include &lt;libxml/HTMLparser.h&gt;</span><br />
<br />
<span class="kw2">class</span> LibXml2ReaderLocator <span class="sy0">:</span> <span class="kw2">public</span> <span class="kw5">QXmlLocator</span> <span class="br0">&#123;</span><br />
<span class="kw2">public</span><span class="sy0">:</span><br />
&nbsp; &nbsp; LibXml2ReaderLocator<span class="br0">&#40;</span>LibXml2Reader<span class="sy0">*</span> r<span class="br0">&#41;</span> <span class="sy0">:</span> reader<span class="br0">&#40;</span>r<span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">int</span> columnNumber<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> const<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw2">virtual</span> <span class="kw4">int</span> lineNumber<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> const<span class="sy0">;</span><br />
<span class="kw2">private</span><span class="sy0">:</span><br />
&nbsp; &nbsp; LibXml2Reader<span class="sy0">*</span> reader<span class="sy0">;</span><br />
<span class="br0">&#125;</span><span class="sy0">;</span><br />
<br />
<span class="kw2">class</span> LibXml2ReaderPrivate <span class="br0">&#123;</span><br />
<span class="kw2">public</span><span class="sy0">:</span><br />
&nbsp; &nbsp; ~LibXml2ReaderPrivate<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
<span class="kw2">private</span><span class="sy0">:</span><br />
&nbsp; &nbsp; LibXml2ReaderPrivate<span class="br0">&#40;</span>LibXml2Reader<span class="sy0">*</span> reader<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw4">static</span> <span class="kw4">void</span> startDocument<span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">static</span> <span class="kw4">void</span> endDocument<span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">static</span> <span class="kw4">void</span> startElement<span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> name<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">**</span> attrs<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">static</span> <span class="kw4">void</span> endElement<span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> name<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">static</span> <span class="kw4">void</span> comment<span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> value<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">static</span> <span class="kw4">void</span> cdataBlock<span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> value<span class="sy0">,</span> <span class="kw4">int</span> len<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">static</span> <span class="kw4">void</span> processingInstruction<span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> target<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> data<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">static</span> <span class="kw4">void</span> characters<span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> ch<span class="sy0">,</span> <span class="kw4">int</span> len<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">static</span> <span class="kw4">void</span> ignorableWhitespace<span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> ch<span class="sy0">,</span> <span class="kw4">int</span> len<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">static</span> <span class="kw4">void</span> internalSubset<span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> name<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> publicId<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> systemId<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw4">void</span> parse<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QXmlInputSource</span><span class="sy0">*</span> input<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; QScopedPointer<span class="sy0">&lt;</span>LibXml2ReaderLocator<span class="sy0">&gt;</span> locator<span class="sy0">;</span><br />
&nbsp; &nbsp; Q_DECLARE_PUBLIC<span class="br0">&#40;</span>LibXml2Reader<span class="br0">&#41;</span><br />
&nbsp; &nbsp; LibXml2Reader<span class="sy0">*</span> q_ptr<span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw5">QXmlEntityResolver</span><span class="sy0">*</span> entityresolver<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw5">QXmlDTDHandler</span><span class="sy0">*</span> &nbsp; &nbsp; dtdhandler<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw5">QXmlContentHandler</span><span class="sy0">*</span> contenthandler<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw5">QXmlErrorHandler</span><span class="sy0">*</span> &nbsp; errorhandler<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw5">QXmlLexicalHandler</span><span class="sy0">*</span> lexicalhandler<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw5">QXmlDeclHandler</span><span class="sy0">*</span> &nbsp; &nbsp;declhandler<span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; xmlParserCtxt<span class="sy0">*</span> context<span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">friend</span> <span class="kw2">class</span> LibXml2ReaderLocator<span class="sy0">;</span><br />
<span class="br0">&#125;</span><span class="sy0">;</span><br />
<br />
LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">LibXml2ReaderPrivate</span><span class="br0">&#40;</span>LibXml2Reader<span class="sy0">*</span> reader<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="sy0">:</span> q_ptr<span class="br0">&#40;</span>reader<span class="br0">&#41;</span><span class="sy0">,</span> entityresolver<span class="br0">&#40;</span>0<span class="br0">&#41;</span><span class="sy0">,</span> dtdhandler<span class="br0">&#40;</span>0<span class="br0">&#41;</span><span class="sy0">,</span> contenthandler<span class="br0">&#40;</span>0<span class="br0">&#41;</span><span class="sy0">,</span> errorhandler<span class="br0">&#40;</span>0<span class="br0">&#41;</span><span class="sy0">,</span> lexicalhandler<span class="br0">&#40;</span>0<span class="br0">&#41;</span><span class="sy0">,</span> declhandler<span class="br0">&#40;</span>0<span class="br0">&#41;</span><span class="sy0">,</span> context<span class="br0">&#40;</span>0<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; this<span class="sy0">-&gt;</span><span class="me3">locator</span>.<span class="me1">reset</span><span class="br0">&#40;</span><span class="kw1">new</span> LibXml2ReaderLocator<span class="br0">&#40;</span>reader<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">parse</span><span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QXmlInputSource</span><span class="sy0">*</span> input<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; htmlSAXHandler handler<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw5">QByteArray</span> arr <span class="sy0">=</span> input<span class="sy0">-&gt;</span><span class="me3">data</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">toLocal8Bit</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*</span> data <span class="sy0">=</span> arr.<span class="me1">data</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; std<span class="sy0">::</span><span class="kw3">memset</span><span class="br0">&#40;</span><span class="sy0">&amp;</span>handler<span class="sy0">,</span> 0<span class="sy0">,</span> <span class="kw3">sizeof</span><span class="br0">&#40;</span>handler<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; handler.<span class="me1">startDocument</span> &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">=</span> <span class="sy0">&amp;</span>LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">startDocument</span><span class="sy0">;</span><br />
&nbsp; &nbsp; handler.<span class="me1">endDocument</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">=</span> <span class="sy0">&amp;</span>LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">endDocument</span><span class="sy0">;</span><br />
&nbsp; &nbsp; handler.<span class="me1">startElement</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=</span> <span class="sy0">&amp;</span>LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">startElement</span><span class="sy0">;</span><br />
&nbsp; &nbsp; handler.<span class="me1">endElement</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=</span> <span class="sy0">&amp;</span>LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">endElement</span><span class="sy0">;</span><br />
&nbsp; &nbsp; handler.<span class="me1">comment</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">=</span> <span class="sy0">&amp;</span>LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">comment</span><span class="sy0">;</span><br />
&nbsp; &nbsp; handler.<span class="me1">cdataBlock</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=</span> <span class="sy0">&amp;</span>LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">cdataBlock</span><span class="sy0">;</span><br />
&nbsp; &nbsp; handler.<span class="me1">processingInstruction</span> <span class="sy0">=</span> <span class="sy0">&amp;</span>LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">processingInstruction</span><span class="sy0">;</span><br />
&nbsp; &nbsp; handler.<span class="me1">characters</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=</span> <span class="sy0">&amp;</span>LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">characters</span><span class="sy0">;</span><br />
&nbsp; &nbsp; handler.<span class="me1">ignorableWhitespace</span> &nbsp; <span class="sy0">=</span> <span class="sy0">&amp;</span>LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">ignorableWhitespace</span><span class="sy0">;</span><br />
&nbsp; &nbsp; handler.<span class="me1">internalSubset</span> &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=</span> <span class="sy0">&amp;</span>LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">internalSubset</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; this<span class="sy0">-&gt;</span><span class="me3">context</span> <span class="sy0">=</span> htmlCreatePushParserCtxt<span class="br0">&#40;</span><span class="sy0">&amp;</span>handler<span class="sy0">,</span> <span class="kw1">this</span><span class="sy0">,</span> data<span class="sy0">,</span> xmlStrlen<span class="br0">&#40;</span><span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span><span class="kw4">const</span> xmlChar<span class="sy0">*&gt;</span><span class="br0">&#40;</span>data<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st0">&quot;&quot;</span><span class="sy0">,</span> XML_CHAR_ENCODING_NONE<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; htmlParseChunk<span class="br0">&#40;</span>this<span class="sy0">-&gt;</span><span class="me3">context</span><span class="sy0">,</span> <span class="kw2">NULL</span><span class="sy0">,</span> 0<span class="sy0">,</span> 1<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; htmlFreeParserCtxt<span class="br0">&#40;</span>this<span class="sy0">-&gt;</span><span class="me3">context</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; xmlCleanupParser<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">startDocument</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; LibXml2ReaderPrivate<span class="sy0">*</span> r <span class="sy0">=</span> <span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span>LibXml2ReaderPrivate<span class="sy0">*&gt;</span><span class="br0">&#40;</span>c<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="sy0">-&gt;</span><span class="me3">startDocument</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">endDocument</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; LibXml2ReaderPrivate<span class="sy0">*</span> r <span class="sy0">=</span> <span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span>LibXml2ReaderPrivate<span class="sy0">*&gt;</span><span class="br0">&#40;</span>c<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="sy0">-&gt;</span><span class="me3">endDocument</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">startElement</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> name<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">**</span> attrs<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; LibXml2ReaderPrivate<span class="sy0">*</span> r <span class="sy0">=</span> <span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span>LibXml2ReaderPrivate<span class="sy0">*&gt;</span><span class="br0">&#40;</span>c<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw5">QXmlAttributes</span> a<span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> i <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>attrs<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span>attrs<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*</span> name &nbsp;<span class="sy0">=</span> <span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>attrs<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*</span> value <span class="sy0">=</span> <span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>attrs<span class="br0">&#91;</span>i<span class="sy0">+</span>1<span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i <span class="sy0">+=</span> <span class="nu0">2</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a.<span class="me1">append</span><span class="br0">&#40;</span>name<span class="sy0">,</span> <span class="st0">&quot;&quot;</span><span class="sy0">,</span> <span class="st0">&quot;&quot;</span><span class="sy0">,</span> value ? value <span class="sy0">:</span> name<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw5">QString</span> uri <span class="sy0">=</span> <span class="st0">&quot;&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw5">QString</span> localName <span class="sy0">=</span> <span class="st0">&quot;&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw5">QString</span> qName <span class="sy0">=</span> <span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>name<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="sy0">-&gt;</span><span class="me3">startElement</span><span class="br0">&#40;</span>uri<span class="sy0">,</span> localName<span class="sy0">,</span> qName<span class="sy0">,</span> a<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">endElement</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> name<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; LibXml2ReaderPrivate<span class="sy0">*</span> r <span class="sy0">=</span> <span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span>LibXml2ReaderPrivate<span class="sy0">*&gt;</span><span class="br0">&#40;</span>c<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="sy0">-&gt;</span><span class="me3">endElement</span><span class="br0">&#40;</span><span class="kw5">QString</span><span class="br0">&#40;</span><span class="st0">&quot;&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="kw5">QString</span><span class="br0">&#40;</span><span class="st0">&quot;&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="kw5">QString</span><span class="br0">&#40;</span><span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>name<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">comment</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> value<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; LibXml2ReaderPrivate<span class="sy0">*</span> r <span class="sy0">=</span> <span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span>LibXml2ReaderPrivate<span class="sy0">*&gt;</span><span class="br0">&#40;</span>c<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>r<span class="sy0">-&gt;</span><span class="me3">lexicalhandler</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; r<span class="sy0">-&gt;</span><span class="me3">lexicalhandler</span><span class="sy0">-&gt;</span><span class="me3">comment</span><span class="br0">&#40;</span><span class="kw5">QString</span><span class="sy0">::</span><span class="me2">fromLocal8Bit</span><span class="br0">&#40;</span><span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>value<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">cdataBlock</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> value<span class="sy0">,</span> <span class="kw4">int</span> len<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; LibXml2ReaderPrivate<span class="sy0">*</span> r <span class="sy0">=</span> <span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span>LibXml2ReaderPrivate<span class="sy0">*&gt;</span><span class="br0">&#40;</span>c<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>r<span class="sy0">-&gt;</span><span class="me3">lexicalhandler</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; r<span class="sy0">-&gt;</span><span class="me3">lexicalhandler</span><span class="sy0">-&gt;</span><span class="me3">startCDATA</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw5">QByteArray</span> arr<span class="br0">&#40;</span><span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>value<span class="br0">&#41;</span><span class="sy0">,</span> len<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="sy0">-&gt;</span><span class="me3">characters</span><span class="br0">&#40;</span>arr<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; r<span class="sy0">-&gt;</span><span class="me3">lexicalhandler</span><span class="sy0">-&gt;</span><span class="me3">endCDATA</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">processingInstruction</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> target<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> data<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; LibXml2ReaderPrivate<span class="sy0">*</span> r <span class="sy0">=</span> <span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span>LibXml2ReaderPrivate<span class="sy0">*&gt;</span><span class="br0">&#40;</span>c<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="sy0">-&gt;</span><span class="me3">processingInstruction</span><span class="br0">&#40;</span><span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>target<span class="br0">&#41;</span><span class="sy0">,</span> <span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>data<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">characters</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> ch<span class="sy0">,</span> <span class="kw4">int</span> len<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; LibXml2ReaderPrivate<span class="sy0">*</span> r <span class="sy0">=</span> <span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span>LibXml2ReaderPrivate<span class="sy0">*&gt;</span><span class="br0">&#40;</span>c<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="sy0">-&gt;</span><span class="me3">characters</span><span class="br0">&#40;</span><span class="kw5">QString</span><span class="sy0">::</span><span class="me2">fromLocal8Bit</span><span class="br0">&#40;</span><span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>ch<span class="br0">&#41;</span><span class="sy0">,</span> len<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">ignorableWhitespace</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> ch<span class="sy0">,</span> <span class="kw4">int</span> len<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; LibXml2ReaderPrivate<span class="sy0">*</span> r <span class="sy0">=</span> <span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span>LibXml2ReaderPrivate<span class="sy0">*&gt;</span><span class="br0">&#40;</span>c<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; r<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="sy0">-&gt;</span><span class="me3">ignorableWhitespace</span><span class="br0">&#40;</span><span class="kw5">QString</span><span class="sy0">::</span><span class="me2">fromLocal8Bit</span><span class="br0">&#40;</span><span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>ch<span class="br0">&#41;</span><span class="sy0">,</span> len<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2ReaderPrivate<span class="sy0">::</span><span class="me2">internalSubset</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="sy0">*</span> c<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> name<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> publicId<span class="sy0">,</span> <span class="kw4">const</span> xmlChar<span class="sy0">*</span> systemId<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; LibXml2ReaderPrivate<span class="sy0">*</span> r <span class="sy0">=</span> <span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span>LibXml2ReaderPrivate<span class="sy0">*&gt;</span><span class="br0">&#40;</span>c<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>r<span class="sy0">-&gt;</span><span class="me3">lexicalhandler</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw5">QString</span> n<span class="br0">&#40;</span><span class="kw5">QString</span><span class="sy0">::</span><span class="me2">fromLocal8Bit</span><span class="br0">&#40;</span><span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>name<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw5">QString</span> p<span class="br0">&#40;</span><span class="kw5">QString</span><span class="sy0">::</span><span class="me2">fromLocal8Bit</span><span class="br0">&#40;</span><span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>publicId<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw5">QString</span> s<span class="br0">&#40;</span><span class="kw5">QString</span><span class="sy0">::</span><span class="me2">fromLocal8Bit</span><span class="br0">&#40;</span><span class="kw2">reinterpret_cast</span><span class="sy0">&lt;</span><span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">*&gt;</span><span class="br0">&#40;</span>systemId<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; r<span class="sy0">-&gt;</span><span class="me3">lexicalhandler</span><span class="sy0">-&gt;</span><span class="me3">startDTD</span><span class="br0">&#40;</span>n<span class="sy0">,</span> p<span class="sy0">,</span> s<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; r<span class="sy0">-&gt;</span><span class="me3">lexicalhandler</span><span class="sy0">-&gt;</span><span class="me3">endDTD</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
<span class="br0">&#125;</span><br />
<br />
LibXml2Reader<span class="sy0">::</span><span class="me2">LibXml2Reader</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="sy0">:</span> d_ptr<span class="br0">&#40;</span><span class="kw1">new</span> LibXml2ReaderPrivate<span class="br0">&#40;</span><span class="kw1">this</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
<span class="br0">&#125;</span><br />
<br />
LibXml2Reader<span class="sy0">::</span><span class="me2">~LibXml2Reader</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">bool</span> LibXml2Reader<span class="sy0">::</span><span class="me2">feature</span><span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QString</span><span class="sy0">&amp;,</span> <span class="kw4">bool</span><span class="sy0">*</span> ok<span class="br0">&#41;</span> <span class="kw4">const</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>ok<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">*</span>ok <span class="sy0">=</span> false<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">return</span> false<span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2Reader<span class="sy0">::</span><span class="me2">setFeature</span><span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QString</span><span class="sy0">&amp;,</span> <span class="kw4">bool</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">bool</span> LibXml2Reader<span class="sy0">::</span><span class="me2">hasFeature</span><span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QString</span><span class="sy0">&amp;</span><span class="br0">&#41;</span> <span class="kw4">const</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> false<span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span><span class="sy0">*</span> LibXml2Reader<span class="sy0">::</span><span class="me2">property</span><span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QString</span><span class="sy0">&amp;,</span> <span class="kw4">bool</span><span class="sy0">*</span> ok<span class="br0">&#41;</span> <span class="kw4">const</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>ok<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">*</span>ok <span class="sy0">=</span> false<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">0</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2Reader<span class="sy0">::</span><span class="me2">setProperty</span><span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QString</span><span class="sy0">&amp;,</span> <span class="kw4">void</span><span class="sy0">*</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">bool</span> LibXml2Reader<span class="sy0">::</span><span class="me2">hasProperty</span><span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QString</span><span class="sy0">&amp;</span><span class="br0">&#41;</span> <span class="kw4">const</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> false<span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2Reader<span class="sy0">::</span><span class="me2">setEntityResolver</span><span class="br0">&#40;</span><span class="kw5">QXmlEntityResolver</span><span class="sy0">*</span> handler<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; Q_D<span class="br0">&#40;</span>LibXml2Reader<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; d<span class="sy0">-&gt;</span><span class="me3">entityresolver</span> <span class="sy0">=</span> handler<span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw5">QXmlEntityResolver</span><span class="sy0">*</span> LibXml2Reader<span class="sy0">::</span><span class="me2">entityResolver</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> <span class="kw4">const</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">const</span> LibXml2ReaderPrivate<span class="sy0">*</span> d <span class="sy0">=</span> this<span class="sy0">-&gt;</span><span class="me3">d_func</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> d<span class="sy0">-&gt;</span><span class="me3">entityresolver</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2Reader<span class="sy0">::</span><span class="me2">setDTDHandler</span><span class="br0">&#40;</span><span class="kw5">QXmlDTDHandler</span><span class="sy0">*</span> handler<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; Q_D<span class="br0">&#40;</span>LibXml2Reader<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; d<span class="sy0">-&gt;</span><span class="me3">dtdhandler</span> <span class="sy0">=</span> handler<span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw5">QXmlDTDHandler</span><span class="sy0">*</span> LibXml2Reader<span class="sy0">::</span><span class="me2">DTDHandler</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> <span class="kw4">const</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">const</span> LibXml2ReaderPrivate<span class="sy0">*</span> d <span class="sy0">=</span> this<span class="sy0">-&gt;</span><span class="me3">d_func</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> d<span class="sy0">-&gt;</span><span class="me3">dtdhandler</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2Reader<span class="sy0">::</span><span class="me2">setContentHandler</span><span class="br0">&#40;</span><span class="kw5">QXmlContentHandler</span><span class="sy0">*</span> handler<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; Q_D<span class="br0">&#40;</span>LibXml2Reader<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; d<span class="sy0">-&gt;</span><span class="me3">contenthandler</span> <span class="sy0">=</span> handler<span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw5">QXmlContentHandler</span><span class="sy0">*</span> LibXml2Reader<span class="sy0">::</span><span class="me2">contentHandler</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> <span class="kw4">const</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">const</span> LibXml2ReaderPrivate<span class="sy0">*</span> d <span class="sy0">=</span> this<span class="sy0">-&gt;</span><span class="me3">d_func</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> d<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2Reader<span class="sy0">::</span><span class="me2">setErrorHandler</span><span class="br0">&#40;</span><span class="kw5">QXmlErrorHandler</span><span class="sy0">*</span> handler<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; Q_D<span class="br0">&#40;</span>LibXml2Reader<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; d<span class="sy0">-&gt;</span><span class="me3">errorhandler</span> <span class="sy0">=</span> handler<span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw5">QXmlErrorHandler</span><span class="sy0">*</span> LibXml2Reader<span class="sy0">::</span><span class="me2">errorHandler</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> <span class="kw4">const</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">const</span> LibXml2ReaderPrivate<span class="sy0">*</span> d <span class="sy0">=</span> this<span class="sy0">-&gt;</span><span class="me3">d_func</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> d<span class="sy0">-&gt;</span><span class="me3">errorhandler</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2Reader<span class="sy0">::</span><span class="me2">setLexicalHandler</span><span class="br0">&#40;</span><span class="kw5">QXmlLexicalHandler</span><span class="sy0">*</span> handler<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; Q_D<span class="br0">&#40;</span>LibXml2Reader<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; d<span class="sy0">-&gt;</span><span class="me3">lexicalhandler</span> <span class="sy0">=</span> handler<span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw5">QXmlLexicalHandler</span><span class="sy0">*</span> LibXml2Reader<span class="sy0">::</span><span class="me2">lexicalHandler</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> <span class="kw4">const</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">const</span> LibXml2ReaderPrivate<span class="sy0">*</span> d <span class="sy0">=</span> this<span class="sy0">-&gt;</span><span class="me3">d_func</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> d<span class="sy0">-&gt;</span><span class="me3">lexicalhandler</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">void</span> LibXml2Reader<span class="sy0">::</span><span class="me2">setDeclHandler</span><span class="br0">&#40;</span><span class="kw5">QXmlDeclHandler</span><span class="sy0">*</span> handler<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; Q_D<span class="br0">&#40;</span>LibXml2Reader<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; d<span class="sy0">-&gt;</span><span class="me3">declhandler</span> <span class="sy0">=</span> handler<span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw5">QXmlDeclHandler</span><span class="sy0">*</span> LibXml2Reader<span class="sy0">::</span><span class="me2">declHandler</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> <span class="kw4">const</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">const</span> LibXml2ReaderPrivate<span class="sy0">*</span> d <span class="sy0">=</span> this<span class="sy0">-&gt;</span><span class="me3">d_func</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> d<span class="sy0">-&gt;</span><span class="me3">declhandler</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">bool</span> LibXml2Reader<span class="sy0">::</span><span class="me2">parse</span><span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QXmlInputSource</span><span class="sy0">&amp;</span> input<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> this<span class="sy0">-&gt;</span><span class="me3">parse</span><span class="br0">&#40;</span><span class="sy0">&amp;</span>input<span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">bool</span> LibXml2Reader<span class="sy0">::</span><span class="me2">parse</span><span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw5">QXmlInputSource</span><span class="sy0">*</span> input<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; Q_D<span class="br0">&#40;</span>LibXml2Reader<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>d<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; d<span class="sy0">-&gt;</span><span class="me3">contenthandler</span><span class="sy0">-&gt;</span><span class="me3">setDocumentLocator</span><span class="br0">&#40;</span>d<span class="sy0">-&gt;</span><span class="me3">locator</span>.<span class="me1">data</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; d<span class="sy0">-&gt;</span><span class="me3">parse</span><span class="br0">&#40;</span>input<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">return</span> true<span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">int</span> LibXml2ReaderLocator<span class="sy0">::</span><span class="me2">columnNumber</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> <span class="kw4">const</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> this<span class="sy0">-&gt;</span><span class="me3">reader</span><span class="sy0">-&gt;</span><span class="me3">d_func</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me3">context</span><span class="sy0">-&gt;</span><span class="me3">input</span><span class="sy0">-&gt;</span><span class="me3">col</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">int</span> LibXml2ReaderLocator<span class="sy0">::</span><span class="me2">lineNumber</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span> <span class="kw4">const</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> this<span class="sy0">-&gt;</span><span class="me3">reader</span><span class="sy0">-&gt;</span><span class="me3">d_func</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me3">context</span><span class="sy0">-&gt;</span><span class="me3">input</span><span class="sy0">-&gt;</span><span class="me3">line</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Использование:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p94253">
        <div class="code cpp-qt" id="p942code53">
&nbsp; &nbsp; <span class="kw5">QByteArray</span> data<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw5">QXmlInputSource</span> src<span class="sy0">;</span><br />
&nbsp; &nbsp; LibXml2Reader reader<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw5">QDomDocument</span> doc<span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="coMULTI">/* здесь читаем данные в data */</span><br />
<br />
&nbsp; &nbsp; src.<span class="me1">setData</span><span class="br0">&#40;</span>data<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; doc.<span class="me1">setContent</span><span class="br0">&#40;</span><span class="sy0">&amp;</span>src<span class="sy0">,</span> <span class="sy0">&amp;</span>reader<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; <span class="coMULTI">/* doc будет содержать дерево DOM, построенное из документа HTML */</span>
        </div>
    </div>
</div>

<p>В файл проекта нужно будет добавить две строки:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p94254">
        <div class="code text" id="p942code54">
INCLUDEPATH += /usr/include/libxml2<br />
LIBS &nbsp; &nbsp; &nbsp; &nbsp;+= -lxml2
        </div>
    </div>
</div>

<p>В <code>INCLUDEPATH</code> помещается путь к заголовочным файлам libxml2, в <code>LIBS</code> — опции компилятора для подключения библиотеки libxml2.</p>
<p>Скачать:</p>
<ul>
<li><a href='http://static.sjinks.info/wp-content/uploads/2011/09/libxml2reader.h'>libxml2reader.h</a></li>
<li><a href='http://static.sjinks.info/wp-content/uploads/2011/09/libxml2reader.cpp'>libxml2reader.cpp</a></li>
</ul>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/qt/942-html-parser-qt/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/c-cpp/qt/942-html-parser-qt/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>OpenMP, параллельный режим и утечки памяти в GNU Standard C++ Library</title>
		<link>http://blog.sjinks.pro/c-cpp/913-openmp-parallel-mode-memory-leak-libstdc/</link>
		<comments>http://blog.sjinks.pro/c-cpp/913-openmp-parallel-mode-memory-leak-libstdc/#comments</comments>
		<pubDate>Sat, 14 May 2011 04:23:09 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[OpenMP]]></category>
		<category><![CDATA[valgrind]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=913</guid>
		<description><![CDATA[Скрестив ужа и ежа, Мичурин получил колючую проволоку Стандартнуя библиотека GNU языка C++ поддерживает так называемый параллельный режим, который предоставляет экспериментальную поддержку параллельных алгоритмов из &#60;algorithm&#62; и &#60;numeric&#62;. Для включения данного режима исходный код нужно компилировать с опеределённым макросом _GLIBCXX_PARALLEL, либо явно подключать заголовочные файлы из &#60;parallel/&#62; и использовать пространство имён __gnu_parallel. В параллельном режиме [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/913-openmp-parallel-mode-memory-leak-libstdc/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Скрестив ужа и ежа, Мичурин получил колючую проволоку</em></h2>
<p>Стандартнуя библиотека GNU языка C++ поддерживает так называемый <dfn><a href="http://gcc.gnu.org/onlinedocs/libstdc++/manual/parallel_mode.html">параллельный режим</a></dfn>, который предоставляет экспериментальную поддержку параллельных алгоритмов из <code>&lt;algorithm&gt;</code> и <code>&lt;numeric&gt;</code>. Для включения данного режима исходный код нужно компилировать с опеределённым макросом <code>_GLIBCXX_PARALLEL</code>, либо явно подключать заголовочные файлы из <code>&lt;parallel/&gt;</code> и использовать пространство имён <code>__gnu_parallel</code>.</p>
<p>В параллельном режиме для реализации параллелизма используется <a href="http://blog.sjinks.pro/tag/openmp/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  OpenMP">OpenMP</a>.</p>
<p>Как оказалось, при использовании в своей программе OpenMP и параллельного режима <code>libstdc++</code> можно столкнуться с очень неприятными и недокументированными особенностями реализации и получить незабываемое «удовольствие» при отладке.<span id="more-913"></span></p>
<p>Есть очень простая тестовая программа, использующая OpenMP:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p91364">
        <div class="code cpp" id="p913code64">
<span class="co2">#include &lt;algorithm&gt;</span><br />
<span class="co2">#include &lt;vector&gt;</span><br />
<span class="co2">#include &lt;string&gt;</span><br />
<span class="co2">#include &lt;cstdlib&gt;</span><br />
<span class="co2">#include &lt;sstream&gt;</span><br />
<br />
<span class="kw4">typedef</span> std<span class="sy4">::</span><span class="me2">vector</span><span class="sy1">&lt;</span>std<span class="sy4">::</span><span class="me2">string</span><span class="sy1">&gt;</span> vector_t<span class="sy4">;</span><br />
<br />
<span class="kw2">template</span><span class="sy1">&lt;</span><span class="kw2">typename</span> T<span class="sy1">&gt;</span><br />
std<span class="sy4">::</span><span class="me2">string</span> toString<span class="br0">&#40;</span><span class="kw4">const</span> T<span class="sy3">&amp;</span> x<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">stringstream</span> converter<span class="sy4">;</span><br />
&nbsp; &nbsp; converter <span class="sy1">&lt;&lt;</span> x<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> converter.<span class="me1">str</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw2">template</span><span class="sy1">&lt;</span><span class="kw2">typename</span> T<span class="sy1">&gt;</span><br />
T gen<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> std<span class="sy4">::</span><span class="kw3">rand</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw2">template</span><span class="sy1">&lt;&gt;</span><br />
std<span class="sy4">::</span><span class="me2">string</span> gen<span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> toString<span class="br0">&#40;</span>std<span class="sy4">::</span><span class="kw3">rand</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw4">int</span> main<span class="br0">&#40;</span><span class="kw4">int</span> argc, <span class="kw4">char</span><span class="sy2">**</span> argv<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; vector_t v1<span class="br0">&#40;</span>65536<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; vector_t v2<span class="br0">&#40;</span>65536<span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; <span class="co2">#pragma omp parallel shared(v1, v2)</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co2">#pragma omp single nowait</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co2">#pragma omp task shared(v1)</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">generate</span><span class="br0">&#40;</span>v1.<span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, v1.<span class="me1">end</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, gen<span class="sy1">&lt;</span>vector_t<span class="sy4">::</span><span class="me2">value_type</span><span class="sy1">&gt;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">generate</span><span class="br0">&#40;</span>v2.<span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, v2.<span class="me1">end</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, gen<span class="sy1">&lt;</span>vector_t<span class="sy4">::</span><span class="me2">value_type</span><span class="sy1">&gt;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">0</span><span class="sy4">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Программа использует два потока для заполнения двух векторов случайными строками. При использовании параллельного режима теоретически может использоваться более двух потоков — <code>libstdc++</code> имеет параллельную версию алгоритма <code>std::generate</code>.</p>
<p>Сборка программы выполняется так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p91365">
        <div class="code bash" id="p913code65">
<span class="kw2">g++</span> <span class="re5">-fopenmp</span> <span class="re5">-O1</span> <span class="re5">-g3</span> test.cpp <span class="re5">-o</span> test1<br />
<span class="kw2">g++</span> <span class="re5">-fopenmp</span> <span class="re5">-O1</span> <span class="re5">-g3</span> -D_GLIBCXX_PARALLEL test.cpp <span class="re5">-o</span> test2
        </div>
    </div>
</div>

<p><code>test1</code> не использует параллельный режим, <code>test2</code> использует.</p>
<p>Самое интересное начинается при запуске обеих программ под <a href="http://blog.sjinks.pro/tag/valgrind/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  valgrind">Valgrind</a> — с целью нахождения утечек памяти.<br />
Запуск осуществляется так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p91366">
        <div class="code bash" id="p913code66">
<span class="kw2">valgrind</span> <span class="re5">--num-callers</span>=20 <span class="re5">--leak-check</span>=<span class="kw2">yes</span> <span class="re5">--leak-resolution</span>=high <span class="re5">--show-reachable</span>=<span class="kw2">yes</span> .<span class="sy0">/</span>test1<br />
<span class="kw2">valgrind</span> <span class="re5">--num-callers</span>=20 <span class="re5">--leak-check</span>=<span class="kw2">yes</span> <span class="re5">--leak-resolution</span>=high <span class="re5">--show-reachable</span>=<span class="kw2">yes</span> .<span class="sy0">/</span>test2
        </div>
    </div>
</div>

<p>Получились такие результаты:</p>
<p><strong>Без использования параллельного режима:</strong></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p91367">
        <div class="code text" id="p913code67">
==10569== HEAP SUMMARY:<br />
==10569== &nbsp; &nbsp; in use at exit: 2,936 bytes in 6 blocks<br />
==10569== &nbsp; total heap usage: 262,152 allocs, 262,146 frees, 75,956,839 bytes allocated<br />
…<br />
==10569== LEAK SUMMARY:<br />
==10569== &nbsp; &nbsp;definitely lost: 0 bytes in 0 blocks<br />
==10569== &nbsp; &nbsp;indirectly lost: 0 bytes in 0 blocks<br />
==10569== &nbsp; &nbsp; &nbsp;possibly lost: 912 bytes in 3 blocks<br />
==10569== &nbsp; &nbsp;still reachable: 2,024 bytes in 3 blocks<br />
==10569== &nbsp; &nbsp; &nbsp; &nbsp; suppressed: 0 bytes in 0 blocks
        </div>
    </div>
</div>

<p>Явных утечек памяти нет; по поводу <code>still reachable</code> разработчики говорят, что <a href="http://www.mail-archive.com/gcc-bugs@gcc.gnu.org/msg224364.html">это не ошибка</a> (я с ними согласен).</p>
<p>Таким образом, при использовании OpenMP и стандартного режима libstdc++ всё выглядит довольно-таки хорошо.</p>
<p><strong>С использованием параллельного режима:</strong></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p91368">
        <div class="code text" id="p913code68">
==10628== HEAP SUMMARY:<br />
==10628== &nbsp; &nbsp; in use at exit: 4,522,599 bytes in 131,078 blocks<br />
==10628== &nbsp; total heap usage: 262,402 allocs, 131,324 frees, 77,022,766 bytes allocated<br />
…<br />
==10628== LEAK SUMMARY:<br />
==10628== &nbsp; &nbsp;definitely lost: 4,519,595 bytes in 131,070 blocks<br />
==10628== &nbsp; &nbsp;indirectly lost: 0 bytes in 0 blocks<br />
==10628== &nbsp; &nbsp; &nbsp;possibly lost: 980 bytes in 5 blocks<br />
==10628== &nbsp; &nbsp;still reachable: 2,024 bytes in 3 blocks<br />
==10628== &nbsp; &nbsp; &nbsp; &nbsp; suppressed: 0 bytes in 0 blocks
        </div>
    </div>
</div>

<p>Сразу бросается в глаза: <strong>definitely lost: 4,519,595 bytes in 131,070 blocks</strong> — это те самые два вектора (2×65536) плюс еще чуть-чуть.</p>
<p>Трасса вызовов выглядит так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p91369">
        <div class="code text" id="p913code69">
==10628== 34 bytes in 1 blocks are possibly lost in loss record 2 of 10<br />
==10628== &nbsp; &nbsp;at 0x4C28B42: operator new(unsigned long) (vg_replace_malloc.c:261)<br />
==10628== &nbsp; &nbsp;by 0x4ECBE6C: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator&lt;char&gt; const&amp;) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.14)<br />
==10628== &nbsp; &nbsp;by 0x402FBB: char* std::string::_S_construct&lt;char*&gt;(char*, char*, std::allocator&lt;char&gt; const&amp;, std::forward_iterator_tag) (basic_string.tcc:138)<br />
==10628== &nbsp; &nbsp;by 0x403002: std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;::basic_string&lt;char*&gt;(char*, char*, std::allocator&lt;char&gt; const&amp;) (basic_string.h:1649)<br />
==10628== &nbsp; &nbsp;by 0x403234: std::string toString&lt;int&gt;(int const&amp;) (sstream:127)<br />
==10628== &nbsp; &nbsp;by 0x401CBD: std::string gen&lt;std::string&gt;() (test.cpp:27)<br />
==10628== &nbsp; &nbsp;by 0x402373: _ZN14__gnu_parallel46__for_each_template_random_access_workstealingIN9__gnu_cxx17__normal_iteratorIPSsNSt9__cxx19986vectorISsSaISsEEEEEPFSsvENS_19__generate_selectorIS8_EENS_12_DummyReductEbEET0_T_SF_SE_RT1_T2_T3_RSJ_NSt15iterator_traitsISF_E15difference_typeE.omp_fn.4 (for_each_selectors.h:77)<br />
==10628== &nbsp; &nbsp;by 0x40D68B: std::string (*__gnu_parallel::__for_each_template_random_access_workstealing&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, std::string (*)(), __gnu_parallel::__generate_selector&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt; &gt;, __gnu_parallel::_DummyReduct, bool&gt;(__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, __gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, std::string (*)(), __gnu_parallel::__generate_selector&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt; &gt;&amp;, __gnu_parallel::_DummyReduct, bool, bool&amp;, std::iterator_traits&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt; &gt;::difference_type))() (workstealing.h:297)<br />
==10628== &nbsp; &nbsp;by 0x40D77C: std::string (*__gnu_parallel::__for_each_template_random_access&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, std::string (*)(), __gnu_parallel::__generate_selector&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt; &gt;, __gnu_parallel::_DummyReduct, bool&gt;(__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, __gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, std::string (*)(), __gnu_parallel::__generate_selector&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt; &gt;&amp;, __gnu_parallel::_DummyReduct, bool, bool&amp;, std::iterator_traits&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt; &gt;::difference_type, __gnu_parallel::_Parallelism))() (for_each.h:86)<br />
==10628== &nbsp; &nbsp;by 0x40D814: void std::__parallel::__generate_switch&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, std::string (*)()&gt;(__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, __gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, std::string (*)(), std::random_access_iterator_tag, __gnu_parallel::_Parallelism) (algo.h:1556)<br />
==10628== &nbsp; &nbsp;by 0x40258C: main.omp_fn.1 (algo.h:1584)<br />
==10628== &nbsp; &nbsp;by 0x53C1A12: ??? (in /usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0)<br />
==10628== &nbsp; &nbsp;by 0x53C3748: ??? (in /usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0)<br />
==10628== &nbsp; &nbsp;by 0x53C1FBD: ??? (in /usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0)<br />
==10628== &nbsp; &nbsp;by 0x57E4D8B: start_thread (pthread_create.c:304)<br />
==10628== &nbsp; &nbsp;by 0x5AE204C: clone (clone.S:112)
        </div>
    </div>
</div>

          
<div class="codebox">
    <div class="the_code" style="" id="p91370">
        <div class="code text" id="p913code70">
==10628== 2,259,752 bytes in 65,534 blocks are definitely lost in loss record 9 of 10<br />
==10628== &nbsp; &nbsp;at 0x4C28B42: operator new(unsigned long) (vg_replace_malloc.c:261)<br />
==10628== &nbsp; &nbsp;by 0x4ECBE6C: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator&lt;char&gt; const&amp;) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.14)<br />
==10628== &nbsp; &nbsp;by 0x402FBB: char* std::string::_S_construct&lt;char*&gt;(char*, char*, std::allocator&lt;char&gt; const&amp;, std::forward_iterator_tag) (basic_string.tcc:138)<br />
==10628== &nbsp; &nbsp;by 0x403002: std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;::basic_string&lt;char*&gt;(char*, char*, std::allocator&lt;char&gt; const&amp;) (basic_string.h:1649)<br />
==10628== &nbsp; &nbsp;by 0x403234: std::string toString&lt;int&gt;(int const&amp;) (sstream:127)<br />
==10628== &nbsp; &nbsp;by 0x401CBD: std::string gen&lt;std::string&gt;() (test.cpp:27)<br />
==10628== &nbsp; &nbsp;by 0x402373: _ZN14__gnu_parallel46__for_each_template_random_access_workstealingIN9__gnu_cxx17__normal_iteratorIPSsNSt9__cxx19986vectorISsSaISsEEEEEPFSsvENS_19__generate_selectorIS8_EENS_12_DummyReductEbEET0_T_SF_SE_RT1_T2_T3_RSJ_NSt15iterator_traitsISF_E15difference_typeE.omp_fn.4 (for_each_selectors.h:77)<br />
==10628== &nbsp; &nbsp;by 0x40D68B: std::string (*__gnu_parallel::__for_each_template_random_access_workstealing&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, std::string (*)(), __gnu_parallel::__generate_selector&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt; &gt;, __gnu_parallel::_DummyReduct, bool&gt;(__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, __gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, std::string (*)(), __gnu_parallel::__generate_selector&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt; &gt;&amp;, __gnu_parallel::_DummyReduct, bool, bool&amp;, std::iterator_traits&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt; &gt;::difference_type))() (workstealing.h:297)<br />
==10628== &nbsp; &nbsp;by 0x40D77C: std::string (*__gnu_parallel::__for_each_template_random_access&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, std::string (*)(), __gnu_parallel::__generate_selector&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt; &gt;, __gnu_parallel::_DummyReduct, bool&gt;(__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, __gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, std::string (*)(), __gnu_parallel::__generate_selector&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt; &gt;&amp;, __gnu_parallel::_DummyReduct, bool, bool&amp;, std::iterator_traits&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt; &gt;::difference_type, __gnu_parallel::_Parallelism))() (for_each.h:86)<br />
==10628== &nbsp; &nbsp;by 0x40D814: void std::__parallel::__generate_switch&lt;__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, std::string (*)()&gt;(__gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, __gnu_cxx::__normal_iterator&lt;std::string*, std::__cxx1998::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; &gt;, std::string (*)(), std::random_access_iterator_tag, __gnu_parallel::_Parallelism) (algo.h:1556)<br />
==10628== &nbsp; &nbsp;by 0x402566: main.omp_fn.0 (algo.h:1584)<br />
==10628== &nbsp; &nbsp;by 0x40297B: main (test.cpp:35)
        </div>
    </div>
</div>

<p>Ключ к пониманию даёт <code>workstealing.h</code> (адрес 0x40D68B в трассе). В коде есть такая строка:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p91371">
        <div class="code cpp" id="p913code71">
<ol class="cpp" style="font-family:monospace;" start="139"><li class="li1"><div class="de1"><span class="co2"># &nbsp; &nbsp; pragma omp parallel shared(__busy) num_threads(__num_threads)</span></div></li>
</ol>
        </div>
    </div>
</div>

<p>Что получается: грубо говоря, следующее:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p91372">
        <div class="code cpp" id="p913code72">
<span class="co2">#pragma omp parallel</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="co2">#pragma omp single nowait</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co2">#pragma omp task</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// …</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co2">#pragma omp parallel num_threads(__num_threads)</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// …</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Есть предположение, что виноват <code>num_threads</code> во вложенном <code>omp parallel</code> (по крайней мере, если убрать <code>num_threads</code>, то утечки исчезают — но последствия изменений я не проверял).</p>
<p>Вроде бы в <code>num_threads</code> криминала нет — вложенный блок <code>omp parallel</code> создаёт новую группу потоков (при условии, что вложенность разрешена — либо через <code>OMP_NESTED=TRUE</code>, либо через вызов <code>omp_set_nested(true)</code>), а не изменяет количество потоков в существующей группе, но где-то что-то не до конца продумано.</p>
<p>Мораль на сегодняшний день такова: при использовании OpenMP параллельный режим глобально лучше не включать; при необходимости использования параллельных алгоритмов использовать алгоритм из пространства имён <code>__gnu_parallel</code> (и ни в коем случае не делать этого внутри блоков OpenMP).</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/913-openmp-parallel-mode-memory-leak-libstdc/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/c-cpp/913-openmp-parallel-mode-memory-leak-libstdc/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>k-путевое слияние на C++</title>
		<link>http://blog.sjinks.pro/c-cpp/911-k-way-merge-sort-cpp/</link>
		<comments>http://blog.sjinks.pro/c-cpp/911-k-way-merge-sort-cpp/#comments</comments>
		<pubDate>Fri, 06 May 2011 11:40:48 +0000</pubDate>
		<dc:creator>Wandering Soul</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[алгоритмы]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=911</guid>
		<description><![CDATA[Пример простейшей реализации k-путевго слиянием Алгоритмы слияния — семейство алгоритмов, последовательно обрабатывающие отсортированные списки и генерирующие один или более отсортированных списков на выходе. Слияние используется в алгоритме сортировки слиянием (например, функция bitonic_merge() в алгоритме битонной сортировки). k-путевое слияние использует k отсортированных списков; в данном примере генерируется один выходной список, размер которого равен размеру всех входных списков. k-путевое [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/911-k-way-merge-sort-cpp/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Пример простейшей реализации k-путевго слиянием</em></h2>
<p>Алгоритмы слияния — семейство алгоритмов, последовательно обрабатывающие отсортированные списки и генерирующие один или более отсортированных списков на выходе. Слияние используется в алгоритме сортировки слиянием (например, функция <code>bitonic_merge()</code> в <strong><a href="http://blog.sjinks.pro/c-cpp/908-bitonic-mergesort-cpp/">алгоритме битонной сортировки</a></strong>).</p>
<p>k-путевое слияние использует <var>k</var> отсортированных списков; в данном примере генерируется один выходной список, размер которого равен размеру всех входных списков.</p>
<p>k-путевое слияние может быть очень эффективно при сортировке очень больших объёмов данных: большой исходный файл разбивается на несколько файлов меньшего размера, каждый из которых можно отсортировать в оперативной памяти; после сортировки получается <var>n</var> отсортированных файлов. Над отсортированными файлами выполняется <a href="http://blog.sjinks.pro/tag/sort/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  сортировка">сортировка</a> многопутевого слияния (возможно, в несколько этапов), на выходе получается отсортированный исходный файл.</p>
<p>Как сортировку, так и слияние можно выполнять параллельно (например, при использовании быстрой сортировки можно использовать конструкцию <code>task</code> из <a href="http://blog.sjinks.pro/tag/openmp/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  OpenMP">OpenMP</a> 3.0; слияния же можно проводить в несколько потоков потоков — например, 100 файлов можно отсортировать в 4 потока, используя 25-путевое слияние — правда, это создаст дополнительную нагрузку на диск).<span id="more-911"></span></p>
<p>Ниже приведена простейшая реализация k-путевого слияния на C++.</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p91175">
        <div class="code cpp" id="p911code75">
<span class="co2">#include &lt;vector&gt;</span><br />
<span class="co2">#include &lt;algorithm&gt;</span><br />
<span class="co2">#include &lt;utility&gt;</span><br />
<span class="co2">#include &lt;functional&gt;</span><br />
<br />
<span class="kw2">template</span><span class="sy1">&lt;</span><span class="kw2">typename</span> InputIterator, <span class="kw2">typename</span> OutputIterator, <span class="kw2">typename</span> Compare<span class="sy1">&gt;</span><br />
OutputIterator n_way_merge<span class="br0">&#40;</span><span class="kw4">const</span> std<span class="sy4">::</span><span class="me2">vector</span><span class="sy1">&lt;</span>std<span class="sy4">::</span><span class="me2">pair</span><span class="sy1">&lt;</span>InputIterator, InputIterator<span class="sy1">&gt;</span> <span class="sy1">&gt;</span><span class="sy3">&amp;</span> in, OutputIterator out, Compare comp<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; OutputIterator res <span class="sy1">=</span> out<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">typedef</span> <span class="kw2">typename</span> std<span class="sy4">::</span><span class="me2">iterator_traits</span><span class="sy1">&lt;</span>InputIterator<span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">value_type</span> value_t<span class="sy4">;</span><br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">vector</span><span class="sy1">&lt;</span>value_t<span class="sy1">&gt;</span> l<span class="br0">&#40;</span>in.<span class="me1">size</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">vector</span><span class="sy1">&lt;</span>std<span class="sy4">::</span><span class="me2">pair</span><span class="sy1">&lt;</span>InputIterator, InputIterator<span class="sy1">&gt;</span> <span class="sy1">&gt;</span> f<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">typedef</span> <span class="kw2">typename</span> std<span class="sy4">::</span><span class="me2">vector</span><span class="sy1">&lt;</span>std<span class="sy4">::</span><span class="me2">pair</span><span class="sy1">&lt;</span>InputIterator, InputIterator<span class="sy1">&gt;</span> <span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">iterator</span> iterator_t<span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; f.<span class="me1">assign</span><span class="br0">&#40;</span>in.<span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, in.<span class="me1">end</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; iterator_t b <span class="sy1">=</span> f.<span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="kw4">size_t</span> i <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span>b <span class="sy3">!</span><span class="sy1">=</span> f.<span class="me1">end</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">pair</span><span class="sy1">&lt;</span>InputIterator, InputIterator<span class="sy1">&gt;</span><span class="sy3">&amp;</span> x <span class="sy1">=</span> <span class="sy2">*</span>b<span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>x.<span class="me1">first</span> <span class="sy1">==</span> x.<span class="me1">second</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b <span class="sy1">=</span> f.<span class="me1">erase</span><span class="br0">&#40;</span>b<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; l.<span class="me1">erase</span><span class="br0">&#40;</span>l.<span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy2">+</span> i<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; l<span class="br0">&#91;</span>i<span class="br0">&#93;</span> <span class="sy1">=</span> <span class="sy2">*</span>x.<span class="me1">first</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy2">++</span>b<span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy2">++</span>i<span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span><span class="sy3">!</span>f.<span class="me1">empty</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">typename</span> std<span class="sy4">::</span><span class="me2">vector</span><span class="sy1">&lt;</span>value_t<span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">iterator</span> p <span class="sy1">=</span> std<span class="sy4">::</span><span class="me2">min_element</span><span class="br0">&#40;</span>l.<span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, l.<span class="me1">end</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, comp<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy2">*</span>out <span class="sy1">=</span> <span class="sy2">*</span>p<span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy2">++</span>out<span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; i <span class="sy1">=</span> p <span class="sy2">-</span> l.<span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy2">++</span>f<span class="br0">&#91;</span>i<span class="br0">&#93;</span>.<span class="me1">first</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>f<span class="br0">&#91;</span>i<span class="br0">&#93;</span>.<span class="me1">first</span> <span class="sy1">==</span> f<span class="br0">&#91;</span>i<span class="br0">&#93;</span>.<span class="me1">second</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f.<span class="me1">erase</span><span class="br0">&#40;</span>f.<span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy2">+</span> i<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; l.<span class="me1">erase</span><span class="br0">&#40;</span>p<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; l<span class="br0">&#91;</span>i<span class="br0">&#93;</span> <span class="sy1">=</span> <span class="sy2">*</span>f<span class="br0">&#91;</span>i<span class="br0">&#93;</span>.<span class="me1">first</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">return</span> out<span class="sy4">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw2">template</span><span class="sy1">&lt;</span><span class="kw2">typename</span> InputIterator, <span class="kw2">typename</span> OutputIterator<span class="sy1">&gt;</span><br />
OutputIterator n_way_merge<span class="br0">&#40;</span><span class="kw4">const</span> std<span class="sy4">::</span><span class="me2">vector</span><span class="sy1">&lt;</span>std<span class="sy4">::</span><span class="me2">pair</span><span class="sy1">&lt;</span>InputIterator, InputIterator<span class="sy1">&gt;</span> <span class="sy1">&gt;</span><span class="sy3">&amp;</span> in, OutputIterator out<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">typedef</span> <span class="kw2">typename</span> std<span class="sy4">::</span><span class="me2">iterator_traits</span><span class="sy1">&lt;</span>InputIterator<span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">value_type</span> value_t<span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> n_way_merge<span class="br0">&#40;</span>in, out, std<span class="sy4">::</span><span class="me2">less</span><span class="sy1">&lt;</span>value_t<span class="sy1">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>Пример использования:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p91176">
        <div class="code cpp" id="p911code76">
&nbsp; &nbsp; <span class="kw4">int</span> a<span class="br0">&#91;</span>5<span class="br0">&#93;</span> <span class="sy1">=</span> <span class="br0">&#123;</span> 10, 20, 30, 40, 50 <span class="br0">&#125;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">int</span> b<span class="br0">&#91;</span>8<span class="br0">&#93;</span> <span class="sy1">=</span> <span class="br0">&#123;</span> 5, 7, 9, 11, 13, 15, 17, 19 <span class="br0">&#125;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">int</span> c<span class="br0">&#91;</span>3<span class="br0">&#93;</span> <span class="sy1">=</span> <span class="br0">&#123;</span> 0, 1, 2 <span class="br0">&#125;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw4">int</span> d<span class="br0">&#91;</span>4<span class="br0">&#93;</span> <span class="sy1">=</span> <span class="br0">&#123;</span> 6, 12, 18, 24 <span class="br0">&#125;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">vector</span><span class="sy1">&lt;</span>std<span class="sy4">::</span><span class="me2">pair</span><span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy2">*</span>, <span class="kw4">int</span><span class="sy2">*</span><span class="sy1">&gt;</span> <span class="sy1">&gt;</span> in<span class="br0">&#40;</span>4<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; in.<span class="me1">push_back</span><span class="br0">&#40;</span>std<span class="sy4">::</span><span class="me2">make_pair</span><span class="br0">&#40;</span>a, a <span class="sy2">+</span> 5<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; in.<span class="me1">push_back</span><span class="br0">&#40;</span>std<span class="sy4">::</span><span class="me2">make_pair</span><span class="br0">&#40;</span>b, b <span class="sy2">+</span> 8<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; in.<span class="me1">push_back</span><span class="br0">&#40;</span>std<span class="sy4">::</span><span class="me2">make_pair</span><span class="br0">&#40;</span>c, c <span class="sy2">+</span> 3<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; in.<span class="me1">push_back</span><span class="br0">&#40;</span>std<span class="sy4">::</span><span class="me2">make_pair</span><span class="br0">&#40;</span>d, d <span class="sy2">+</span> 4<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">vector</span><span class="sy1">&lt;</span><span class="kw4">int</span><span class="sy1">&gt;</span> out<span class="br0">&#40;</span>5<span class="sy2">+</span>8<span class="sy2">+</span>3<span class="sy2">+</span>4<span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; n_way_merge<span class="br0">&#40;</span>in, out.<span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span>std<span class="sy4">::</span><span class="kw4">size_t</span> i<span class="sy1">=</span><span class="nu0">0</span><span class="sy4">;</span> i<span class="sy1">&lt;</span>out.<span class="me1">size</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span> <span class="sy2">++</span>i<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">cout</span> <span class="sy1">&lt;&lt;</span> out<span class="br0">&#91;</span>i<span class="br0">&#93;</span> <span class="sy1">&lt;&lt;</span> <span class="st0">&quot; &quot;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">cout</span> <span class="sy1">&lt;&lt;</span> std<span class="sy4">::</span><span class="me2">endl</span><span class="sy4">;</span>
        </div>
    </div>
</div>

<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/911-k-way-merge-sort-cpp/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/c-cpp/911-k-way-merge-sort-cpp/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Bitonic Mergesort на C++</title>
		<link>http://blog.sjinks.pro/c-cpp/908-bitonic-mergesort-cpp/</link>
		<comments>http://blog.sjinks.pro/c-cpp/908-bitonic-mergesort-cpp/#comments</comments>
		<pubDate>Sat, 16 Apr 2011 11:16:53 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[алгоритмы]]></category>
		<category><![CDATA[сортировка]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=908</guid>
		<description><![CDATA[Битонная сортировка в стиле STL Битонная сортировка слиянием (bitonic mergesort) — параллельный алгоритм сортировки, рекурсивно разделяющий входную последовательность на сортированные последовательности меньшего размера. Алгоритм битонной сортировки может выполняться параллельно, потому что каждая операция разделения независима от всех других операций. #include &#60;iterator&#62; #include &#60;functional&#62; #include &#60;algorithm&#62; namespace { template&#60;typename Iterator, typename Comp&#62; void bitonic_merge(bool flag, Iterator [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/908-bitonic-mergesort-cpp/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Битонная <a href="http://blog.sjinks.pro/tag/sort/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  сортировка">сортировка</a> в стиле STL</em></h2>
<p>Битонная сортировка слиянием (<a href="http://en.wikipedia.org/wiki/Bitonic_sort">bitonic mergesort</a>) — параллельный алгоритм сортировки, рекурсивно разделяющий входную последовательность на сортированные последовательности меньшего размера.</p>
<p>Алгоритм битонной сортировки может выполняться параллельно, потому что каждая операция разделения независима от всех других операций.<br />
<span id="more-908"></span></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p90878">
        <div class="code cpp" id="p908code78">
<span class="co2">#include &lt;iterator&gt;</span><br />
<span class="co2">#include &lt;functional&gt;</span><br />
<span class="co2">#include &lt;algorithm&gt;</span><br />
<br />
<span class="kw2">namespace</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw2">template</span><span class="sy1">&lt;</span><span class="kw2">typename</span> Iterator, <span class="kw2">typename</span> Comp<span class="sy1">&gt;</span><br />
&nbsp; &nbsp; <span class="kw4">void</span> bitonic_merge<span class="br0">&#40;</span><span class="kw4">bool</span> flag, Iterator begin, Iterator end, Iterator middle, Comp c<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Iterator x<span class="br0">&#40;</span>begin<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Iterator y<span class="br0">&#40;</span>middle<span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span> <span class="sy4">;</span> y <span class="sy3">!</span><span class="sy1">=</span> end<span class="sy4">;</span> <span class="sy2">++</span>x, <span class="sy2">++</span>y<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>flag <span class="sy3">!</span><span class="sy1">=</span> c<span class="br0">&#40;</span><span class="sy2">*</span>x, <span class="sy2">*</span>y<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">swap</span><span class="br0">&#40;</span><span class="sy2">*</span>x, <span class="sy2">*</span>y<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; x <span class="sy1">=</span> begin<span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; y <span class="sy1">=</span> middle<span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">typename</span> std<span class="sy4">::</span><span class="me2">iterator_traits</span><span class="sy1">&lt;</span>Iterator<span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">difference_type</span> halfsize <span class="sy1">=</span> std<span class="sy4">::</span><span class="me2">distance</span><span class="br0">&#40;</span>begin, middle<span class="br0">&#41;</span> <span class="sy1">&gt;&gt;</span> <span class="nu0">1</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>halfsize<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">advance</span><span class="br0">&#40;</span>x, halfsize<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">advance</span><span class="br0">&#40;</span>y, halfsize<span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bitonic_merge<span class="br0">&#40;</span>flag, begin, middle, x, c<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bitonic_merge<span class="br0">&#40;</span>flag, middle, end, y, c<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="kw2">template</span><span class="sy1">&lt;</span><span class="kw2">typename</span> Iterator, <span class="kw2">typename</span> Comp<span class="sy1">&gt;</span><br />
&nbsp; &nbsp; <span class="kw4">void</span> bitonic_sort_private<span class="br0">&#40;</span><span class="kw4">bool</span> flag, Iterator begin, Iterator end, Comp c<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">typename</span> std<span class="sy4">::</span><span class="me2">iterator_traits</span><span class="sy1">&lt;</span>Iterator<span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">difference_type</span> size <span class="sy1">=</span> std<span class="sy4">::</span><span class="me2">distance</span><span class="br0">&#40;</span>begin, end<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>size <span class="sy1">&lt;=</span> 1<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; Iterator m<span class="br0">&#40;</span>begin<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; std<span class="sy4">::</span><span class="me2">advance</span><span class="br0">&#40;</span>m, size <span class="sy1">&gt;&gt;</span> 1<span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; bitonic_sort_private<span class="br0">&#40;</span>flag, begin, m, c<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; bitonic_sort_private<span class="br0">&#40;</span><span class="sy3">!</span>flag, m, end, c<span class="br0">&#41;</span><span class="sy4">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; bitonic_merge<span class="br0">&#40;</span>flag, begin, end, m, c<span class="br0">&#41;</span><span class="sy4">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
<span class="br0">&#125;</span><span class="sy4">;</span><br />
<br />
<span class="kw2">template</span><span class="sy1">&lt;</span><span class="kw2">typename</span> Iterator<span class="sy1">&gt;</span><br />
<span class="kw4">void</span> bitonic_sort<span class="br0">&#40;</span>Iterator begin, Iterator end<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw4">typedef</span> <span class="kw2">typename</span> std<span class="sy4">::</span><span class="me2">iterator_traits</span><span class="sy1">&lt;</span>Iterator<span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">value_type</span> value_t<span class="sy4">;</span><br />
&nbsp; &nbsp; bitonic_sort_private<span class="br0">&#40;</span><span class="kw2">true</span>, begin, end, std<span class="sy4">::</span><span class="me2">less</span><span class="sy1">&lt;</span>value_t<span class="sy1">&gt;</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="kw2">template</span><span class="sy1">&lt;</span><span class="kw2">typename</span> Iterator, <span class="kw2">typename</span> Comp<span class="sy1">&gt;</span><br />
<span class="kw4">void</span> bitonic_sort<span class="br0">&#40;</span>Iterator begin, Iterator end, Comp c<span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; &nbsp; bitonic_sort_private<span class="br0">&#40;</span><span class="kw2">true</span>, begin, end, c<span class="br0">&#41;</span><span class="sy4">;</span><br />
<span class="br0">&#125;</span>
        </div>
    </div>
</div>

<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/c-cpp/908-bitonic-mergesort-cpp/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/c-cpp/908-bitonic-mergesort-cpp/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

