﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-金庆的专栏-随笔分类-1. C/C++</title><link>http://www.cppblog.com/jinq0123/category/5137.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 18 Nov 2022 02:33:25 GMT</lastBuildDate><pubDate>Fri, 18 Nov 2022 02:33:25 GMT</pubDate><ttl>60</ttl><item><title>How are dtLinks created in NavMesh</title><link>http://www.cppblog.com/jinq0123/archive/2022/11/18/229525.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Fri, 18 Nov 2022 02:03:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/11/18/229525.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/229525.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/11/18/229525.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/229525.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/229525.html</trackback:ping><description><![CDATA[<h1 id="how-are-dtlinks-created-in-navmesh">How are dtLinks created in NavMesh</h1>
<p>(Jin Qing's Column, Nov., 2022)</p>
<h2 id="dtlink"><code>dtLink</code></h2>
<p><code>dtLink</code> defines a link between 2 polygons.
It is an internal data structure.</p>
<p>A <code>dtLink</code> is owned by its source polygon.</p>
<h3 id="how-link-is-used">How link is used</h3>
<p>The links are used in <code>findPath()</code>, to search
all the neighbor polygons, from the current best polygon.</p>
<h3 id="fields-of-dtlink">fields of <code>dtLink</code></h3>
<p><code>dtLink</code> has 2 required fields:</p>
<ul>
<li>neighbor: the neighbor polygon reference that is linked to.</li>
<li>edge: index of the polygon edge that owns this link.
It is used in getPortalPoints() and raycast().</li>
</ul>
<p>If the link is a boundary link, which links to other tile, then it has more fields:</p>
<ul>
<li>side: defines on which side the link is. 8 sides.
It is used in findPath() and raycast().</li>
<li>bmin: defines the minimum sub-edge area.</li>
<li>bmax: defines the maximum sub-edge area.
bmin and bmax are used in portal finding.</li>
</ul>
<h2 id="how-are-links-created">How are links created</h2>
<p>Links are not saved to navmesh file. They are created on navmesh loading in <code>addTile()</code>.</p>
<p><code>dtNavMesh::addTile()</code> add a tile to the navmesh. A tile is a square block of the map.</p>
<p>The main job of <code>dtNavMesh::addTile()</code> is to create links inside this tile and between this tile and other tiles.
Actually a block indexed by (x, y) of constant size has many layers for multi-floor map.
A <code>dtMeshTile</code> is actually a layer with an index of (x, y, layer).</p>
<p>5 steps to create all links:</p>
<h3 id="1-connect-internal-links">1. Connect internal links</h3>
<p><code>connectIntLinks()</code> iterates all the polygons in the tile and create links for them
by the help of neighbors information of the polygons.</p>
<h3 id="2-base-off-mesh-connections">2. Base off-mesh connections</h3>
<p><code>baseOffMeshLinks()</code> bases off-mesh connections to their starting polygons and connect connections inside the tile.</p>
<p>Off-mesh connection is between 2 points which are inside a tile or between 2 adjacent tiles.</p>
<p>For each off-mesh connection, there creates a specific polygon consisting of 2 vertices.
See <code>DT_POLYTYPE_OFFMESH_CONNECTION</code>.</p>
<p><code>baseOffMeshLinks()</code> creates 2 links for each off-mesh connection:</p>
<ul>
<li>From the off-mesh connection polygon to the source polygon</li>
<li>From the source polygon to the off-mesh connection polygon</li>
</ul>
<p>The destinaton polygon of the off-mesh connection is skipped here.</p>
<h3 id="3-connect-external-off-mesn-links-within-this-tile">3. Connect external off-mesn links within this tile</h3>
<p><code>connectExtOffMeshLinks()</code> with the source and target tile be this tile.</p>
<p><code>connectExtOffMeshLinks()</code> searches off-mesh connections that are from this tile to the target tile
by checking the side direction of the connection.</p>
<p>It creates a link from off-mesh connection polygon to the target tile.
For bidirectional connection, it also creates a link from the target polygon to the off-mesh connection polygon.</p>
<p>So for each off-mesh connection of this tile, 3 or 4 links are created by baseOffMeshLinks() and connectExtOffMeshLinks(),
one on the source polygon, one on the destination polygon and 1/2 on the off-mesh connection polygon.</p>
<h3 id="4-connect-with-layers-in-current-tile">4. Connect with layers in current tile</h3>
<p>For each layer other than this layer in this tile:</p>
<ul>
<li>Create links from this layer to other layer</li>
<li>Create links from other layer to this layer</li>
<li>Create links of the off-mesh connection from this layer to other layer</li>
<li>Create links of the off-mesh connection from other layer to this layer</li>
</ul>
<h3 id="5-connect-with-neighbour-tiles">5. Connect with neighbour tiles</h3>
<p>Check 9 neighbor tiles' layers, and create links just like previous step:</p>
<ul>
<li>Create links from this layer to neighnor layer</li>
<li>Create links from neighnor layer to this layer</li>
<li>Create links of the off-mesh connection from this layer to neighnor layer</li>
<li>Create links of the off-mesh connection from neighnor layer to this layer</li>
</ul>
<p>By now, for every off-mesh connection of all the loaded tiles, 3/4 links are created.</p>
<h2 id="reference">Reference</h2>
<ul>
<li>https://blog.csdn.net/icebergliu1234/article/details/80322392</li>
</ul>
<img src ="http://www.cppblog.com/jinq0123/aggbug/229525.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-11-18 10:03 <a href="http://www.cppblog.com/jinq0123/archive/2022/11/18/229525.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ parameter passing rules</title><link>http://www.cppblog.com/jinq0123/archive/2022/10/29/229466.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sat, 29 Oct 2022 03:01:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/10/29/229466.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/229466.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/10/29/229466.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/229466.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/229466.html</trackback:ping><description><![CDATA[<h1>C++ parameter passing rules</h1><p style="box-sizing: border-box; outline: 0px; margin: 0px 0px 16px; padding: 0px; font-size: 16px; color: #4d4d4d; line-height: 26px; overflow: auto hidden; overflow-wrap: break-word; font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif; font-variant-ligatures: no-common-ligatures; background-color: #ffffff;">From: https://www.modernescpp.com/index.php/c-core-guidelines-how-to-pass-function-parameters</p><p style="box-sizing: border-box; outline: 0px; margin: 0px 0px 16px; padding: 0px; font-size: 16px; color: #4d4d4d; line-height: 26px; overflow: auto hidden; overflow-wrap: break-word; font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif; font-variant-ligatures: no-common-ligatures; background-color: #ffffff;">Parameter passing expression rules:</p><ul style="box-sizing: border-box; outline: 0px; margin: 0px 0px 24px; padding: 0px; list-style-position: initial; list-style-image: initial; font-size: 16px; overflow: auto hidden; overflow-wrap: break-word; color: rgba(0, 0, 0, 0.75); font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif; font-variant-ligatures: no-common-ligatures; background-color: #ffffff;"><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.15: Prefer simple and conventional ways of passing information</li><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.16: For &#8220;in&#8221; parameters, pass cheaply-copied types by value and others by reference to const</li><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.17: For &#8220;in-out&#8221; parameters, pass by reference to non-const</li><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.18: For &#8220;consume&#8221; parameters, pass by X&amp;&amp; and std::move the parameter</li><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.19: For &#8220;forward&#8221; parameters, pass by TP&amp;&amp; and only std::forward the parameter</li><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.20: For &#8220;out&#8221; output values, prefer return values to output parameters</li><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.21: To return multiple &#8220;out&#8221; values, prefer returning a tuple or struct</li><li style="box-sizing: border-box; outline: 0px; margin: 8px 0px 0px 32px; padding: 0px; list-style: disc; overflow-wrap: break-word;">F.60: Prefer T* over T&amp; when &#8220;no argument&#8221; is a valid option</li></ul><img src ="http://www.cppblog.com/jinq0123/aggbug/229466.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-10-29 11:01 <a href="http://www.cppblog.com/jinq0123/archive/2022/10/29/229466.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Naming Conventions for Accessors</title><link>http://www.cppblog.com/jinq0123/archive/2022/09/22/229427.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 22 Sep 2022 08:02:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2022/09/22/229427.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/229427.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2022/09/22/229427.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/229427.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/229427.html</trackback:ping><description><![CDATA[<h1>Naming Conventions for Accessors<br />
</h1>
<p style="box-sizing: inherit; margin-top: 0px; margin-bottom: 1rem; hyphens: auto;">from:&nbsp;<a href="http://cginternals.github.io/guidelines/articles/">C++ Programming Guidelines (cginternals.github.io)</a><br />
<br />
</p>
<p>
When naming accessors within classes, non-trivial getters and queries, i.e., those that perform calculations, you should prepended&nbsp;<code style="box-sizing: inherit; font-family: &quot;Source Code Pro&quot;, monospace; font-size: 14.4px; padding: 0.2rem 0.4rem; color: #186d94; background-color: #f7f7f9; border-radius: 0.25rem;">get</code>. All other getters have no prefix and setters have the&nbsp;<code style="box-sizing: inherit; font-family: &quot;Source Code Pro&quot;, monospace; font-size: 14.4px; padding: 0.2rem 0.4rem; color: #186d94; background-color: #f7f7f9; border-radius: 0.25rem;">set</code>&nbsp;prefix.<br />
<br />
</p><div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all;"><span style="color: #0000ff;">class</span>&nbsp;Object<br />{<br /><span style="color: #0000FF; ">public</span>:<br />&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;radius()&nbsp;<span style="color: #0000FF; ">const</span>;<br />&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;setRadius(<span style="color: #0000FF; ">int</span>&nbsp;value);<br /><br />&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;getPerimeter();<br /><br /><span style="color: #0000FF; ">private</span>:<br />&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;m_radius;<br />};<br /><br /><span style="color: #0000FF; ">int</span>&nbsp;Object::radius()&nbsp;<span style="color: #0000FF; ">const</span><br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;m_radius;<br />}<br /><br /><span style="color: #0000FF; ">void</span>&nbsp;Object::setRadius(<span style="color: #0000FF; ">int</span>&nbsp;value)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;m_radius&nbsp;=&nbsp;value;<br />}<br /><br /><span style="color: #0000FF; ">int</span>&nbsp;Object::getPerimeter()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;2&nbsp;*&nbsp;pi&nbsp;*&nbsp;m_radius;<br />}</div><img src ="http://www.cppblog.com/jinq0123/aggbug/229427.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2022-09-22 16:02 <a href="http://www.cppblog.com/jinq0123/archive/2022/09/22/229427.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visual Studio 2019 Compiler Hangs</title><link>http://www.cppblog.com/jinq0123/archive/2021/07/31/217764.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sat, 31 Jul 2021 07:16:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/07/31/217764.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217764.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/07/31/217764.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217764.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217764.html</trackback:ping><description><![CDATA[# Visual Studio 2019 Compiler Hangs<br /><br />(金庆的专栏 2021.7)<br /><br />Discovered by my colleague Shen Yichai:<br />```<br />Share a interesting MS Build bug:<br />For file a.cpp, enable optimization for Win64 or XSX. <br />The MSBuild always compiling without error and ending (infinite compile). <br />The PS5 (clang) does not have this issue.<br />```<br /><br />The simplified code:<br />```<br /><span style="color: #800000; font-family: Courier;">struct Tag</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;int v;</span><br /><span style="color: #800000; font-family: Courier;">};</span><br /><br /><span style="color: #800000; font-family: Courier;">void Goo(Tag* r, Tag* a)</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;r-&gt;v = a-&gt;v;</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">void Foo(Tag* pos0, Tag* pos)</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;for (int j = 0; j &lt; 4; j++)</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; if (j == 0) {</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; 8; i++) {</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Goo(pos0++, pos);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Goo(pos0++, pos);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; else {</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; 8; i++) {</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Goo(pos0++, pos);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Goo(pos0++, pos);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;}</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">int main()</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;Foo(nullptr, nullptr);</span><br /><span style="color: #800000; font-family: Courier;">}</span><br />```<br /><br />The default release configuration can build correctly.<br />But if "Properties -&gt; C/C++ -&gt; Optimization -&gt; Whole Program optimization" (/GL) of file or project is changed to "No", <br />the compilation will take a long time as 5 minutes.<br /><br />```<br />Microsoft Visual Studio Community 2019<br />Version 16.9.5<br />VisualStudio.16.Release/16.9.5+31229.75<br />Microsoft .NET Framework<br />Version 4.8.04084<br />```<img src ="http://www.cppblog.com/jinq0123/aggbug/217764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-07-31 15:16 <a href="http://www.cppblog.com/jinq0123/archive/2021/07/31/217764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Fbx File Format Identifier</title><link>http://www.cppblog.com/jinq0123/archive/2021/05/30/217692.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 30 May 2021 01:55:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2021/05/30/217692.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217692.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2021/05/30/217692.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217692.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217692.html</trackback:ping><description><![CDATA[# Fbx File Format Identifier<br /><br />(金庆的专栏 2021.5)<br /><br />Print the list of FBX file format identifiers.<br /><br />FBX SDK FbxExporter can set the file format identifier which is an int parameter.<br />The commnet says: User does not need to specify it by default.<br />If not specified, plugin will detect the file format according to file suffix automatically.<br /><br />FBX SDK 2020 automatically set it to the latest binary format, which can not be parsed by "Autodesk FBX Converter 2013".<br />We need to specify the format identifier for FBX Converter 2013.<br />But there is no specification of this parameter.<br />We use the following code to display all the valid format identifiers and their descriptions.<br /><br />```<br />#include &lt;fbxsdk.h&gt;<br />#include &lt;cassert&gt;<br /><br />int main()<br />{<br />&nbsp;&nbsp;&nbsp; FbxManager* myManager = FbxManager::Create();<br />&nbsp;&nbsp;&nbsp; assert(myManager);<br /><br />&nbsp;&nbsp;&nbsp; FbxIOSettings* ios = FbxIOSettings::Create(myManager, IOSROOT);<br />&nbsp;&nbsp;&nbsp; myManager-&gt;SetIOSettings(ios);<br /><br />&nbsp;&nbsp;&nbsp; int lFormatCount = myManager-&gt;GetIOPluginRegistry()-&gt;GetWriterFormatCount();<br />&nbsp;&nbsp;&nbsp; for (int lFormatIndex = 0; lFormatIndex &lt; lFormatCount; lFormatIndex++)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FbxString lDesc = myManager-&gt;GetIOPluginRegistry()-&gt;GetWriterFormatDescription(lFormatIndex);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("Format index %d: %s\n", lFormatIndex, (const char*)lDesc);<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; return 0;<br />}<br />```<br /><br />Output:<br />```<br />Format index 0: FBX binary (*.fbx)<br />Format index 1: FBX ascii (*.fbx)<br />Format index 2: FBX encrypted (*.fbx)<br />Format index 3: FBX 6.0 binary (*.fbx)<br />Format index 4: FBX 6.0 ascii (*.fbx)<br />Format index 5: FBX 6.0 encrypted (*.fbx)<br />Format index 6: AutoCAD DXF (*.dxf)<br />Format index 7: Alias OBJ (*.obj)<br />Format index 8: Collada DAE (*.dae)<br />Format index 9: Biovision BVH (*.bvh)<br />Format index 10: Motion Analysis HTR (*.htr)<br />Format index 11: Motion Analysis TRC (*.trc)<br />Format index 12: Acclaim ASF (*.asf)<br />Format index 13: Acclaim AMC (*.amc)<br />Format index 14: Vicon C3D (*.c3d)<br />Format index 15: Adaptive Optics AOA (*.aoa)<br />Format index 16: Superfluo MCD (*.mcd)<br />```<br /><br />FBX Converter 2013 will error "File is corrupted" for files exported as *.fbx file format: -1, 0, 2, 5.<br />Ascii format (1, 4) and FBX 6.0 binary (3) are OK.<br /><img src ="http://www.cppblog.com/jinq0123/aggbug/217692.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2021-05-30 09:55 <a href="http://www.cppblog.com/jinq0123/archive/2021/05/30/217692.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>查找内存错误</title><link>http://www.cppblog.com/jinq0123/archive/2019/12/16/217028.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Mon, 16 Dec 2019 10:03:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2019/12/16/217028.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/217028.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2019/12/16/217028.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/217028.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/217028.html</trackback:ping><description><![CDATA[查找内存错误<br /><br />(金庆的专栏 2019.12)<br /><br />服务器进程有个偶发的崩溃，breakpad 上传的 minidump 显示调用栈不是出错的代码点，怀疑是内存错误。<br /><br />从日志分析可能触发出错的指令，然后在内网调试环境下测试，很幸运地连续有几次很容易重现了。<br /><br />后来反复测试可知，发送某个特殊 GM 指令 200 次就会出现一次错误，一般会在 100 次内出现。<br />但是以代码反复执行千次万次都不能重现，估计与时间有关，需要手动操作延续一段时间后才会触发。<br /><br />出错点多数在 `boost::property_tree::ini_parser::read_ini()` 中，如下：<br /><br />```<br /><span style="color: #0000ff; font-family: Courier;">[Thread debugging using libthread_db enabled]</span><br /><span style="color: #0000ff; font-family: Courier;">Using host libthread_db library "/lib64/libthread_db.so.1".</span><br /><span style="color: #0000ff; font-family: Courier;">Core was generated by `./GMServer.dbg'.</span><br /><span style="color: #0000ff; font-family: Courier;">Program terminated with signal 11, Segmentation fault.</span><br /><span style="color: #0000ff; font-family: Courier;">#0&nbsp; 0x00000000010ca227 in tcmalloc::SLL_Next(void*) ()</span><br /><span style="color: #0000ff; font-family: Courier;">Missing separate debuginfos, use: debuginfo-install glibc-2.17-105.el7.x86_64 libgcc-4.8.5-4.el7.x86_64 libstdc++-4.8.5-4.el7.x86_64 zlib-1.2.7-15.el7.x86_64</span><br /><span style="color: #0000ff; font-family: Courier;">(gdb) bt</span><br /><span style="color: #0000ff; font-family: Courier;">#0&nbsp; 0x00000000010ca227 in tcmalloc::SLL_Next(void*) ()</span><br /><span style="color: #0000ff; font-family: Courier;">#1&nbsp; 0x00000000010ca2b8 in tcmalloc::SLL_TryPop(void**, void**) ()</span><br /><span style="color: #0000ff; font-family: Courier;">#2&nbsp; 0x00000000010ca715 in tcmalloc::ThreadCache::FreeList::TryPop(void**) ()</span><br /><span style="color: #0000ff; font-family: Courier;">#3&nbsp; 0x00000000011ebe6c in tc_newarray ()</span><br /><span style="color: #0000ff; font-family: Courier;">#4&nbsp; 0x00007efddb7d4c69 in std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator&lt;char&gt; const&amp;) () from /lib64/libstdc++.so.6</span><br /><span style="color: #0000ff; font-family: Courier;">#5&nbsp; 0x0000000000a18153 in std::string::_S_construct&lt;char*&gt; (__beg=0x3f6c8b9 "LobbyServer]", __end=0x3f6c8c4 "]", __a=...) at /usr/include/c++/4.8.2/bits/basic_string.tcc:138</span><br /><span style="color: #0000ff; font-family: Courier;">#6&nbsp; 0x00007efddb7d641c in std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt; &gt;::basic_string(std::string const&amp;, unsigned long, unsigned long) ()</span><br /><span style="color: #0000ff; font-family: Courier;">&nbsp;&nbsp; from /lib64/libstdc++.so.6</span><br /><span style="color: #0000ff; font-family: Courier;">#7&nbsp; 0x00007efddb7d6462 in std::string::substr(unsigned long, unsigned long) const () from /lib64/libstdc++.so.6</span><br /><span style="color: #0000ff; font-family: Courier;">#8&nbsp; 0x0000000000a3c3be in boost::property_tree::ini_parser::read_ini&lt;boost::property_tree::basic_ptree&lt;std::string, std::string, std::less&lt;std::string&gt; &gt; &gt; (stream=..., pt=...)</span><br /><span style="color: #0000ff; font-family: Courier;">&nbsp;&nbsp;&nbsp; at /var/tmp/src/f4f4f712-7894-4d98-83dd-b91be8e0555e/Linux-Debug/003_servers/../000_BaseLib/3RdParty/boost/include/boost/property_tree/ini_parser.hpp:111</span><br /><span style="color: #0000ff; font-family: Courier;">#9&nbsp; 0x0000000000a3b2f0 in boost::property_tree::ini_parser::read_ini&lt;boost::property_tree::basic_ptree&lt;std::string, std::string, std::less&lt;std::string&gt; &gt; &gt; (</span><br /><span style="color: #0000ff; font-family: Courier;">&nbsp;&nbsp;&nbsp; filehelp="cfg.ini", pt=..., loc=...)</span><br /><span style="color: #0000ff; font-family: Courier;">&nbsp;&nbsp;&nbsp; at /var/tmp/src/f4f4f712-7894-4d98-83dd-b91be8e0555e/Linux-Debug/003_servers/../000_BaseLib/3RdParty/boost/include/boost/property_tree/ini_parser.hpp:169</span><br /><span style="color: #0000ff; font-family: Courier;">...</span><br /><span style="color: #0000ff; font-family: Courier;">#27 0x00007efddba27dc5 in start_thread () from /lib64/libpthread.so.0</span><br /><span style="color: #0000ff; font-family: Courier;">#28 0x00007efddaf341cd in clone () from /lib64/libc.so.6</span><br /><span style="color: #0000ff; font-family: Courier;">(gdb) q</span><br />```<br /><br />但是 property_tree 是实践证明可靠的库，暂时不去怀疑它。<br />其他代码有 uWS 处理HTTP 请求，用 hiredis 读写 Redis。<br />这些库先假定是正确的，先查看自己的代码，因为相关代码较少，可以肉眼查错，可惜只查到些无关的小错误。<br /><br />然后到处添加调试日志，跟踪变量的构造与析构。<br />因为 uWS 中用到了一个用户自定义数据，有一个 new/delete 操作，容易出内存错误，重点就是这个数据是否存在野指针。<br />但是看上去正常。<br /><br />肉眼查代码不行，就要用工具了。<br /><br />首先添加 -fstack-protector-all 编译参数，这个参数其实无论如何都应该早就加上的，用来检测函数调用时栈破坏。<br />同时在自定义用户数据使用和析构时检查自身数据是否有效，如某个成员变量总是设为 0x5a, 析构时才把它置为 0xcc.<br />崩溃依旧，但上述内存检查正常。<br /><br />再使用一个 Address Sanitizer, 只需要添加编译选项 -fsanitize=address 即可。<br />它用来检查堆内存是否存在非法操作。<br />但是这个不能和 tcmalloc 共用，我需要更改现有代码，然后链接 asan 库，终于可以运行起来了。<br />如果存在 tcmalloc 调用，进程启动时就会崩溃。<br /><br />效果很好，准确报告 "double-free" 错误：<br />```<br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-192-168-21-31 bin]$ gdb GMServer.dbg</span><br /><span style="color: #0000ff; font-family: Courier;">GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7</span><br /><span style="color: #0000ff; font-family: Courier;">Copyright (C) 2013 Free Software Foundation, Inc.</span><br /><span style="color: #0000ff; font-family: Courier;">License GPLv3+: GNU GPL version 3 or later &lt;http://gnu.org/licenses/gpl.html&gt;</span><br /><span style="color: #0000ff; font-family: Courier;">This is free software: you are free to change and redistribute it.</span><br /><span style="color: #0000ff; font-family: Courier;">There is NO WARRANTY, to the extent permitted by law.&nbsp; Type "show copying"</span><br /><span style="color: #0000ff; font-family: Courier;">and "show warranty" for details.</span><br /><span style="color: #0000ff; font-family: Courier;">This GDB was configured as "x86_64-redhat-linux-gnu".</span><br /><span style="color: #0000ff; font-family: Courier;">For bug reporting instructions, please see:</span><br /><span style="color: #0000ff; font-family: Courier;">&lt;http://www.gnu.org/software/gdb/bugs/&gt;...</span><br /><span style="color: #0000ff; font-family: Courier;">Reading symbols from /home/jinqing/valkyrie/Runtime_ZT_QA/bin/GMServer.dbg...done.</span><br /><span style="color: #0000ff; font-family: Courier;">(gdb) r</span><br /><span style="color: #0000ff; font-family: Courier;">Starting program: /home/jinqing/valkyrie/Runtime_ZT_QA/bin/GMServer.dbg</span><br /><span style="color: #0000ff; font-family: Courier;">[Thread debugging using libthread_db enabled]</span><br /><span style="color: #0000ff; font-family: Courier;">Using host libthread_db library "/lib64/libthread_db.so.1".</span><br /><span style="color: #0000ff; font-family: Courier;">iLogLevel:1</span><br /><span style="color: #0000ff; font-family: Courier;">[New Thread 0x7ffff3724700 (LWP 1010)]</span><br /><span style="color: #0000ff; font-family: Courier;">[New Thread 0x7ffff2c1d700 (LWP 1011)]</span><br /><span style="color: #0000ff; font-family: Courier;">[New Thread 0x7ffff2116700 (LWP 1012)]</span><br /><span style="color: #0000ff; font-family: Courier;">[New Thread 0x7ffff160f700 (LWP 1013)]</span><br /><span style="color: #0000ff; font-family: Courier;">[New Thread 0x7ffff0b08700 (LWP 1014)]</span><br /><span style="color: #0000ff; font-family: Courier;">=================================================================</span><br /><span style="color: #0000ff; font-family: Courier;">==1005== ERROR: AddressSanitizer: attempting double-free on 0x6004000270d0:</span><br /><span style="color: #0000ff; font-family: Courier;">&nbsp;&nbsp;&nbsp; #0 0x7ffff4e60dd9 (/usr/lib64/libasan.so.0.0.0+0x15dd9)</span><br /><span style="color: #0000ff; font-family: Courier;">&nbsp;&nbsp;&nbsp; #1 0x1570e8d (/home/jinqing/valkyrie/Runtime_ZT_QA/bin/GMServer.dbg+0x1570e8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d)</span><br /><span style="color: #0000ff; font-family: Courier;">0x6004000270d0 is located 0 bytes inside of 5-byte region [0x6004000270d0,0x6004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 000270d5)</span><br /><span style="color: #0000ff; font-family: Courier;">freed by thread T0 here:</span><br /><span style="color: #0000ff; font-family: Courier;">&nbsp;&nbsp;&nbsp; #0 0x7ffff4e60dd9 (/usr/lib64/libasan.so.0.0.0+0x15dd9)</span><br /><span style="color: #0000ff; font-family: Courier;">&nbsp;&nbsp;&nbsp; #1 0x1570e8d (/home/jinqing/valkyrie/Runtime_ZT_QA/bin/GMServer.dbg+0x1570e8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d)</span><br /><span style="color: #0000ff; font-family: Courier;">previously allocated by thread T0 here:</span><br /><span style="color: #0000ff; font-family: Courier;">&nbsp;&nbsp;&nbsp; #0 0x7ffff4e60ef9 (/usr/lib64/libasan.so.0.0.0+0x15ef9)</span><br /><span style="color: #0000ff; font-family: Courier;">&nbsp;&nbsp;&nbsp; #1 0x157179e (/home/jinqing/valkyrie/Runtime_ZT_QA/bin/GMServer.dbg+0x157179&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e)</span><br /><span style="color: #0000ff; font-family: Courier;">Thread T4 created by T0 here:</span><br /><span style="color: #0000ff; font-family: Courier;">&nbsp;&nbsp;&nbsp; #0 0x7ffff4e55a0a (/usr/lib64/libasan.so.0.0.0+0xaa0a)</span><br /><span style="color: #0000ff; font-family: Courier;">&nbsp;&nbsp;&nbsp; #1 0x13fc796 (/home/jinqing/valkyrie/Runtime_ZT_QA/bin/GMServer.dbg+0x13fc79&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6)</span><br /><span style="color: #0000ff; font-family: Courier;">==1005== ABORTING</span><br /><span style="color: #0000ff; font-family: Courier;">[Thread 0x7ffff160f700 (LWP 1013) exited]</span><br /><span style="color: #0000ff; font-family: Courier;">[Thread 0x7ffff2116700 (LWP 1012) exited]</span><br /><span style="color: #0000ff; font-family: Courier;">[Thread 0x7ffff2c1d700 (LWP 1011) exited]</span><br /><span style="color: #0000ff; font-family: Courier;">[Thread 0x7ffff3724700 (LWP 1010) exited]</span><br /><span style="color: #0000ff; font-family: Courier;">[Thread 0x7ffff7fe77c0 (LWP 1005) exited]</span><br /><span style="color: #0000ff; font-family: Courier;">[Inferior 1 (process 1005) exited with code 01]</span><br /><span style="color: #0000ff; font-family: Courier;">Missing separate debuginfos, use: debuginfo-install glibc-2.17-105.el7.x86_64 li&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; basan-4.8.5-39.el7.x86_64 libgcc-4.8.5-4.el7.x86_64 libstdc++-4.8.5-4.el7.x86_64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; zlib-1.2.7-15.el7.x86_64</span><br /><span style="color: #0000ff; font-family: Courier;">(gdb)</span><br />```<br /><br />因为用了 gcc 4.8, 所以asan没有函数名输出，gcc 4.9 以上就会有函数名了。<br />但是不要紧，用 nm 可以搜到函数名：<br /><br />```<br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-192-168-21-31 bin]$ nm GMServer.dbg | grep 1570e</span><br /><span style="color: #0000ff; font-family: Courier;">0000000001570e50 T freeReplyObject</span><br /><span style="color: #0000ff; font-family: Courier;">0000000001570ef0 T redisReaderFree</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-192-168-21-31 bin]$ nm GMServer.dbg | grep 15717</span><br /><span style="color: #0000ff; font-family: Courier;">0000000001571750 t createStringObject</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-192-168-21-31 bin]$ nm GMServer.dbg | grep 13fc7</span><br /><span style="color: #0000ff; font-family: Courier;">00000000013fc700 t _ZN5boost6detail23set_current_thread_dataEPNS0_16thread_data_baseE</span><br /><span style="color: #0000ff; font-family: Courier;">00000000013fc7d0 T _ZN5boost6thread21start_thread_noexceptERKNS_17thread_attributesE</span><br /><span style="color: #0000ff; font-family: Courier;">00000000013fc750 T _ZN5boost6thread21start_thread_noexceptEv</span><br /><span style="color: #0000ff; font-family: Courier;">00000000013fc740 T _ZN5boost6threadC1Ev</span><br /><span style="color: #0000ff; font-family: Courier;">00000000013fc740 T _ZN5boost6threadC2Ev</span><br /><span style="color: #0000ff; font-family: Courier;">[jinqing@host-192-168-21-31 bin]$ ^C</span><br />```<br /><br />显示为 freeReplyObject() 调用为 "double-free".<br /><br />有了这个提示，查代码就简单了。原来查 uWS 的用户数据 new/delete 是方向性错误，<br />Redis 也有个 delete 操作，即返回的 ReplyObject 需要调用 freeReplyObject().<br />直接搜索一遍就找到了那个多余的 freeReplyObject. <br /><br />原来是 ReplyObject 保存为一个成员变量，每次 Redis 操作完成后需要调用 freeReplyObject() 并将该成员设为空。<br />同时析构函数中也会判断该成员，非空则调用 freeReplyObject().<br />但是有个每 60s 执行一次的 Ping 操作，调用了 freeReplyObject(), 但是没有置空。<br />同时 GM 指令也触发了一次 Redis 对象重置，再次调用了 freeReplyObject()。<br /><br />正确的做法是不用成员变量，每次都用临时变量就行了，但是用成员变量可以少写一行声明，写代码较方便。<br />为了少改代码，仍然保持为成员变量，仅把缺的置空补上了。<br />同时析构中的 freeReplyObject() 是没必要的，改成断言成员为空。<br /><br />添了一行代码，然后测试，发现错误不出现了。如果不加这行置空，将 Ping 间隔缩小，结果出错概率大大增加了。<br />由此确认，错误点已找到并修正了。<br /><img src ="http://www.cppblog.com/jinq0123/aggbug/217028.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2019-12-16 18:03 <a href="http://www.cppblog.com/jinq0123/archive/2019/12/16/217028.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>std::thread 中的异常会丢失调用栈</title><link>http://www.cppblog.com/jinq0123/archive/2019/09/26/216860.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 26 Sep 2019 09:19:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2019/09/26/216860.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/216860.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2019/09/26/216860.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/216860.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/216860.html</trackback:ping><description><![CDATA[# std::thread 中的异常会丢失调用栈<br /><br />(金庆的专栏 2019.9)<br /><br />主函数中的异常生成core文件能看到调用栈，<br />但是 std::thread 子线程中的异常生成 core 文件的调用栈如下：<br /><br />```<br />Program received signal SIGABRT, Aborted.<br />[Switching to Thread 0x7f18f00ab700 (LWP 32340)]<br />0x00007f19007335f7 in raise () from /lib64/libc.so.6<br />(gdb) bt<br />#0&nbsp; 0x00007f19007335f7 in raise () from /lib64/libc.so.6<br />#1&nbsp; 0x00007f1900734ce8 in abort () from /lib64/libc.so.6<br />#2&nbsp; 0x00007f19010379d5 in __gnu_cxx::__verbose_terminate_handler() () from /lib64/libstdc++.so.6<br />#3&nbsp; 0x00007f1901035946 in ?? () from /lib64/libstdc++.so.6<br />#4&nbsp; 0x00007f1901035973 in std::terminate() () from /lib64/libstdc++.so.6<br />#5&nbsp; 0x00007f190108c2b5 in ?? () from /lib64/libstdc++.so.6<br />#6&nbsp; 0x00007f19012e7dc5 in start_thread () from /lib64/libpthread.so.0<br />#7&nbsp; 0x00007f19007f41cd in clone () from /lib64/libc.so.6<br />(gdb)<br />```<br /><br />调用栈丢失使调试无法找到问题点。<br /><br />据说 GCC 8 修正了该问题。<br /><br />参考：<br />* [C++ uncaught exception in worker thread](https://stackoverflow.com/questions/48535100/c-uncaught-exception-in-worker-thread)<br />* [Bug 55917 - Impossible to find/debug unhandled exceptions in an std::thread](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55917)<br /><img src ="http://www.cppblog.com/jinq0123/aggbug/216860.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2019-09-26 17:19 <a href="http://www.cppblog.com/jinq0123/archive/2019/09/26/216860.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用赋值代替 protobuf CopyFrom()</title><link>http://www.cppblog.com/jinq0123/archive/2019/04/04/216338.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 04 Apr 2019 09:57:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2019/04/04/216338.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/216338.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2019/04/04/216338.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/216338.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/216338.html</trackback:ping><description><![CDATA[# 用赋值代替 protobuf CopyFrom()<br /><br />示例：[Replace protobuf CopyFrom with assignment](https://github.com/tensorflow/tensorflow/commit/9501c4104125fb8c2c2d2e837fc2dd8a24034d52)<br /><br />protobuf 生成的 C++ 代码中，因为 CopyFrom() 可以接受任何 Message 作为参数，<br />所以有可能在2个不同类型的消息之间复制。<br /><br />```<br /><span style="font-family: Courier; color: #800000;">&nbsp; void CopyFrom(const ::google::protobuf::Message&amp; from) final;</span><br /><span style="font-family: Courier; color: #800000;">&nbsp; void CopyFrom(const PlayerData&amp; from);</span><br />```<br /><br />而赋值操作可以保证类型正确。<br /><br />```<br /><span style="font-family: Courier; color: #800000;">class PlayerData : public ::google::protobuf::Message {</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;public:</span><br /><span style="font-family: Courier; color: #800000;">&nbsp; ...</span><br /><span style="font-family: Courier; color: #800000;">&nbsp; inline PlayerData&amp; operator=(const PlayerData&amp; from) {</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp;&nbsp; CopyFrom(from);</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp;&nbsp; return *this;</span><br /><span style="font-family: Courier; color: #800000;">&nbsp; }</span><br /><span style="font-family: Courier; color: #800000;">&nbsp; #if LANG_CXX11</span><br /><span style="font-family: Courier; color: #800000;">&nbsp; inline PlayerData&amp; operator=(PlayerData&amp;&amp; from) noexcept {</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp;&nbsp; ...</span><br /><span style="font-family: Courier; color: #800000;">&nbsp; }</span><br /><span style="font-family: Courier; color: #800000;">&nbsp; #endif</span><br />```<br /><br />类型不一致时编译会报错：<br />```<br /><span style="color: #0000ff;">error: no match for &#8216;operator=&#8217; (operand types are &#8216;a::PlayerData&#8217; and &#8216;a::HeroInfo&#8217;)</span><br />```<br /><br />发现自己用了多年的 CopyFrom() 都是错误的使用。<img src ="http://www.cppblog.com/jinq0123/aggbug/216338.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2019-04-04 17:57 <a href="http://www.cppblog.com/jinq0123/archive/2019/04/04/216338.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>vs2017 linux 编译输出改成 vs 格式</title><link>http://www.cppblog.com/jinq0123/archive/2018/11/21/216073.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 21 Nov 2018 02:57:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2018/11/21/216073.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/216073.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2018/11/21/216073.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/216073.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/216073.html</trackback:ping><description><![CDATA[<div>vs2017 linux 编译输出改成 vs 格式</div><div></div><div><div>(金庆的专栏 2018.11)</div></div><div></div><div><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #008000; ">#</span><span style="color: #008000; ">!/usr/bin/python&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #008000; ">#</span><span style="color: #008000; ">&nbsp;-*-&nbsp;coding:&nbsp;utf-8&nbsp;-*-&nbsp;&nbsp;</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; "><br /></span><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #000000; "></span><span style="color: #800000; ">'''</span><span style="color: #800000; "><br /></span><span style="color: #008080; ">&nbsp;5</span>&nbsp;<span style="color: #800000; ">gcc2vs.py<br /></span><span style="color: #008080; ">&nbsp;6</span>&nbsp;<span style="color: #800000; "><br /></span><span style="color: #008080; ">&nbsp;7</span>&nbsp;<span style="color: #800000; ">功能：<br /></span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #800000; ">将剪切板中gcc的编译输出格式转成vs格式，用于vs跳转到错误行。<br /></span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #800000; ">vs2017&nbsp;linux&nbsp;编译输出为&nbsp;gcc&nbsp;格式，无法点击跳转，如：<br /></span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #800000; ">/var/tmp/src/db<img src="http://www.cppblog.com/Images/dot.gif"  alt="" />e/Linux-Debug/Src/Team.cpp:16:1:&nbsp;错误：&#8216;x&#8217;不是一个类型名<br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #800000; ">须转为vs格式,&nbsp;如<br /></span><span style="color: #008080; ">12</span>&nbsp;<span style="color: #800000; ">/var/tmp/src/db<img src="http://www.cppblog.com/Images/dot.gif"  alt="" />e/Linux-Debug/Src/Team.cpp(16):1:&nbsp;错误：&#8216;x&#8217;不是一个类型名<br /></span><span style="color: #008080; ">13</span>&nbsp;<span style="color: #800000; "><br /></span><span style="color: #008080; ">14</span>&nbsp;<span style="color: #800000; ">如何使用：<br /></span><span style="color: #008080; ">15</span>&nbsp;<span style="color: #800000; "><br /></span><span style="color: #008080; ">16</span>&nbsp;<span style="color: #800000; ">首先须安装&nbsp;python,&nbsp;并安装&nbsp;pyperclip<br /></span><span style="color: #008080; ">17</span>&nbsp;<span style="color: #800000; ">pip&nbsp;install&nbsp;pyperclip<br /></span><span style="color: #008080; ">18</span>&nbsp;<span style="color: #800000; "><br /></span><span style="color: #008080; ">19</span>&nbsp;<span style="color: #800000; ">假设本文件为&nbsp;d:/tools/gcc2vs.py,<br /></span><span style="color: #008080; ">20</span>&nbsp;<span style="color: #800000; ">vs设置外部工具：工具-&gt;外部工具-&gt;添加<br /></span><span style="color: #008080; ">21</span>&nbsp;<span style="color: #800000; ">&nbsp;&nbsp;标题：gcc2vs(&amp;V)<br /></span><span style="color: #008080; ">22</span>&nbsp;<span style="color: #800000; ">&nbsp;&nbsp;命令：python.exe<br /></span><span style="color: #008080; ">23</span>&nbsp;<span style="color: #800000; ">&nbsp;&nbsp;参数：d:/tools/gcc2vs.py<br /></span><span style="color: #008080; ">24</span>&nbsp;<span style="color: #800000; ">&nbsp;&nbsp;选中"使用输出窗口"<br /></span><span style="color: #008080; ">25</span>&nbsp;<span style="color: #800000; "><br /></span><span style="color: #008080; ">26</span>&nbsp;<span style="color: #800000; ">参考：VS2010手动添加外部工具和快捷键&nbsp;&nbsp;<br /></span><span style="color: #008080; ">27</span>&nbsp;<span style="color: #800000; ">https://www.cnblogs.com/ChinaHook/p/4698733.html<br /></span><span style="color: #008080; ">28</span>&nbsp;<span style="color: #800000; "><br /></span><span style="color: #008080; ">29</span>&nbsp;<span style="color: #800000; ">当Linux构建输出后，点击输出窗口，ctrl-A&nbsp;选择全部，ctrl-C&nbsp;复制输出到剪切板，<br /></span><span style="color: #008080; ">30</span>&nbsp;<span style="color: #800000; ">然后&nbsp;alt-T,V&nbsp;运行添加的外部工具&nbsp;gcc2vs(&amp;V),&nbsp;更改输出格式，然后就可以点击错误跳转了。<br /></span><span style="color: #008080; ">31</span>&nbsp;<span style="color: #800000; "></span><span style="color: #800000; ">'''</span><span style="color: #000000; "><br /></span><span style="color: #008080; ">32</span>&nbsp;<span style="color: #000000; "><br /></span><span style="color: #008080; ">33</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;re<br /></span><span style="color: #008080; ">34</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">import</span><span style="color: #000000; ">&nbsp;pyperclip<br /></span><span style="color: #008080; ">35</span>&nbsp;<span style="color: #000000; "><br /></span><span style="color: #008080; ">36</span>&nbsp;<span style="color: #000000; "></span><span style="color: #008000; ">#</span><span style="color: #008000; ">&nbsp;待替换的格式</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">37</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">pattern&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;re.compile(r</span><span style="color: #800000; ">'</span><span style="color: #800000; ">/var/tmp/src/<img src="http://www.cppblog.com/Images/dot.gif"  alt="" /><img src="http://www.cppblog.com/Images/dot.gif"  alt="" />..-<img src="http://www.cppblog.com/Images/dot.gif"  alt="" />.-<img src="http://www.cppblog.com/Images/dot.gif"  alt="" />.-<img src="http://www.cppblog.com/Images/dot.gif"  alt="" />.-<img src="http://www.cppblog.com/Images/dot.gif"  alt="" /><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /><img src="http://www.cppblog.com/Images/dot.gif"  alt="" /><img src="http://www.cppblog.com/Images/dot.gif"  alt="" />/Linux-Debug/(.*):([0-9]*):([0-9]*):&nbsp;</span><span style="color: #800000; ">'</span><span style="color: #000000; ">)<br /></span><span style="color: #008080; ">38</span>&nbsp;<span style="color: #000000; "><br /></span><span style="color: #008080; ">39</span>&nbsp;<span style="color: #000000; ">test_lines_src&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #800000; ">'''</span><span style="color: #800000; "><br /></span><span style="color: #008080; ">40</span>&nbsp;<span style="color: #800000; ">/var/tmp/src/db71a8ec-90bb-2838-98df-2dd35e71166e/Linux-Debug/003_servers/103_LobbyServer/Src/Team.cpp:16:1:&nbsp;错误：&#8216;x&#8217;不是一个类型名<br /></span><span style="color: #008080; ">41</span>&nbsp;<span style="color: #800000; ">生成失败。<br /></span><span style="color: #008080; ">42</span>&nbsp;<span style="color: #800000; "></span><span style="color: #800000; ">'''</span><span style="color: #000000; "><br /></span><span style="color: #008080; ">43</span>&nbsp;<span style="color: #000000; ">test_lines_dst&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #800000; ">'''</span><span style="color: #800000; "><br /></span><span style="color: #008080; ">44</span>&nbsp;<span style="color: #800000; ">003_servers/103_LobbyServer/Src/Team.cpp(16):1:&nbsp;错误：&#8216;x&#8217;不是一个类型名<br /></span><span style="color: #008080; ">45</span>&nbsp;<span style="color: #800000; ">生成失败。<br /></span><span style="color: #008080; ">46</span>&nbsp;<span style="color: #800000; "></span><span style="color: #800000; ">'''</span><span style="color: #000000; "><br /></span><span style="color: #008080; ">47</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">assert</span><span style="color: #000000; ">&nbsp;test_lines_dst&nbsp;</span><span style="color: #000000; ">==</span><span style="color: #000000; ">&nbsp;re.sub(pattern,&nbsp;r</span><span style="color: #800000; ">'</span><span style="color: #800000; ">\1(\2):\3:&nbsp;</span><span style="color: #800000; ">'</span><span style="color: #000000; ">,&nbsp;test_lines_src)<br /></span><span style="color: #008080; ">48</span>&nbsp;<span style="color: #000000; "><br /></span><span style="color: #008080; ">49</span>&nbsp;<span style="color: #000000; "></span><span style="color: #008000; ">#</span><span style="color: #008000; ">&nbsp;剪切板中的gcc格式输出</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">50</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">src&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;pyperclip.paste()<br /></span><span style="color: #008080; ">51</span>&nbsp;<span style="color: #000000; "></span><span style="color: #008000; ">#</span><span style="color: #008000; ">&nbsp;转成vs格式</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">52</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">dst&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;re.sub(pattern,&nbsp;r</span><span style="color: #800000; ">'</span><span style="color: #800000; ">\1(\2):\3:&nbsp;</span><span style="color: #800000; ">'</span><span style="color: #000000; ">,&nbsp;src)<br /></span><span style="color: #008080; ">53</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">print</span><span style="color: #000000; ">(dst)<br /></span><span style="color: #008080; ">54</span>&nbsp;<span style="color: #000000; "></span></div></div><img src ="http://www.cppblog.com/jinq0123/aggbug/216073.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2018-11-21 10:57 <a href="http://www.cppblog.com/jinq0123/archive/2018/11/21/216073.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>为 LiteIDE 添加选中标记</title><link>http://www.cppblog.com/jinq0123/archive/2018/01/06/215458.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sat, 06 Jan 2018 03:05:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2018/01/06/215458.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/215458.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2018/01/06/215458.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/215458.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/215458.html</trackback:ping><description><![CDATA[<div>为 LiteIDE 添加选中标记<br /><br />(金庆的专栏 2018.1)<br /><br />"[Eclipse Mark Occurrences](http://www.eclipse.org/pdt/help/html/mark_occurrences.htm)"<br />可以在滚动条旁边显示文中所有选中的标记，<br />可以选中某个变量显示有多少引用。不过 GoClipse 没有 "Mark Occurrences" 功能。<br />VS code 有此功能。<br /><br />LiteIDE 对于build错误会显示这种标记，所以感觉可以依此实现"Mark Occurrences"。<br /><br />首先找到了打标记的功能。标记用到颜色，所以搜'QColor', 找到了：<br />```c++<br />QColor markTypeColor(LiteApi::EditorNaviagteType type)<br />```<br /><br />相关的接口会用到：<br />```c++<br />&nbsp;&nbsp;&nbsp; void insertNavigateMark(int line, LiteApi::EditorNaviagteType type, const QString &amp;msg, const char* tag);<br />&nbsp;&nbsp;&nbsp; void clearAllNavigateMark(LiteApi::EditorNaviagteType types, const char *tag);<br />```<br /><br />寻找选中时触发标记的代码，选中或搜索时会有圆角框圈出，搜"find", 找到：<br />```c++<br />if (!m_findExpression.isEmpty()) {<br />&nbsp;&nbsp;&nbsp; if (!findInBlock(block,m_findExpression,pos,m_findFlags,cur)) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; ...<br />&nbsp;&nbsp;&nbsp; painter.drawRoundedRect(offsetX+left,r.top()+l.y(),right-left,l.height(),3,3);<br />} else if (!m_selectionExpression.isEmpty()) {<br />&nbsp;&nbsp;&nbsp; if (!findInBlock(block,m_selectionExpression,pos,QTextDocument::FindWholeWords,cur)) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; ...<br />&nbsp;&nbsp;&nbsp; painter.drawRoundedRect(offsetX+left,r.top()+l.y(),right-left,l.height(),3,3);<br />}<br />```<br /><br />发现画方框仅在可视区域。续继查找 m_findExpression 和 m_selectionExpression 更改处，<br />添加 'updateNavigateMarks()'<br /><br />```c++<br />void LiteEditorWidgetBase::setFindOption(LiteApi::FindOption *opt)<br />{<br />&nbsp;&nbsp;&nbsp; ...<br />+&nbsp;&nbsp; updateNavigateMarks(LiteApi::EditorNavigateFind);<br />&nbsp;&nbsp;&nbsp; viewport()-&gt;update();<br />}<br />```<br /><br />```c++<br />void LiteEditorWidgetBase::slotSelectionChanged()<br />{<br />&nbsp;&nbsp;&nbsp; ...<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_selectionExpression.setPattern(pattern);<br />+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; updateNavigateMarks(LiteApi::EditorNavigateSelection);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; viewport()-&gt;update();<br />&nbsp;&nbsp;&nbsp; ...<br />}<br />```<br /><br />须添加2个新的类型：<br />```c++<br />enum EditorNaviagteType{<br />&nbsp;&nbsp;&nbsp; EditorNavigateNormal = 1,<br />&nbsp;&nbsp;&nbsp; EditorNavigateWarning = 2,<br />&nbsp;&nbsp;&nbsp; EditorNavigateError = 4,<br />&nbsp;&nbsp;&nbsp; EditorNavigateReload = 8,<br />+&nbsp;&nbsp; EditorNavigateFind = 16,<br />+&nbsp;&nbsp; EditorNavigateSelection = 32,<br />&nbsp;&nbsp;&nbsp; EditorNavigateBad = EditorNavigateWarning|EditorNavigateError<br />};<br />```<br /><br />搜索 `EditorNavigateWarning`, 找到因新增类型须更改优先级表和颜色函数。<br /><br />```c++<br />const int PRIORITYLIST_LENGTH = 7;<br />const LiteApi::EditorNaviagteType MARKTYPE_PRIORITYLIST[PRIORITYLIST_LENGTH] = {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ..., LiteApi::EditorNavigateFind, LiteApi::EditorNavigateSelection, ...<br />&nbsp;&nbsp;&nbsp; };<br />...<br />inline QColor markTypeColor(LiteApi::EditorNaviagteType type) {<br />&nbsp;&nbsp;&nbsp; switch(type) {<br />&nbsp;&nbsp;&nbsp; ...<br />&nbsp;&nbsp;&nbsp; case LiteApi::EditorNavigateNormal:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Qt::darkGreen;<br />&nbsp;&nbsp;&nbsp; case LiteApi::EditorNavigateReload:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Qt::darkBlue;<br />&nbsp;&nbsp;&nbsp; }<br />}<br />```<br /><br />更新标记时先清空，然后逐行搜索添加标记：<br />```c++<br />// Update selections or find marks.<br />void LiteEditorWidgetBase::updateNavigateMarks(LiteApi::EditorNaviagteType type)<br />{<br />&nbsp;&nbsp;&nbsp; clearAllNavigateMark(type, "");<br />&nbsp;&nbsp;&nbsp; ...<br /><br />&nbsp;&nbsp;&nbsp; QTextDocument *doc = this-&gt;document();<br />&nbsp;&nbsp;&nbsp; for (QTextBlock it = doc-&gt;begin(); it != doc-&gt;end(); it = it.next())<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!needToMarkBlock(it, type))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int lineNumber = it.blockNumber() + 1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; insertNavigateMark(lineNumber, type, QString("%1: %2").arg(lineNumber).arg(it.text()), "");<br />&nbsp;&nbsp;&nbsp; }<br />}<br /><br />bool LiteEditorWidgetBase::needToMarkBlock(<br />&nbsp;&nbsp;&nbsp; const QTextBlock &amp;block, LiteApi::EditorNaviagteType type) const<br />{<br />&nbsp;&nbsp;&nbsp; ...<br />&nbsp;&nbsp;&nbsp; if (LiteApi::EditorNavigateFind == type)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return findInBlock(block, m_findExpression, pos, m_findFlags, cur);<br />&nbsp;&nbsp;&nbsp; if (LiteApi::EditorNavigateSelection == type)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return findInBlock(block, m_selectionExpression, pos,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; QTextDocument::FindWholeWords, cur);<br />&nbsp;&nbsp;&nbsp; return false;<br />}<br />```<br /><br />已合并主干：<br />```<br />Revision: 43f4954b0b802eccbbf451136be600bfcec71f27<br />Author: Jin Qing &lt;jinq0123@163.com&gt;<br />Date: 18.1.5 19:08:26<br />Message:<br />Add "Mark Occurrences" function that marks selections and findings.<br /><br />----<br />Modified: liteidex/src/api/liteeditorapi/liteeditorapi.h<br />Modified: liteidex/src/plugins/liteeditor/liteeditorwidgetbase.cpp<br />Modified: liteidex/src/plugins/liteeditor/liteeditorwidgetbase.h<br />```</div><img src ="http://www.cppblog.com/jinq0123/aggbug/215458.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2018-01-06 11:05 <a href="http://www.cppblog.com/jinq0123/archive/2018/01/06/215458.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>asio 协程中 yield</title><link>http://www.cppblog.com/jinq0123/archive/2017/12/07/215397.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 07 Dec 2017 06:51:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2017/12/07/215397.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/215397.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2017/12/07/215397.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/215397.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/215397.html</trackback:ping><description><![CDATA[<div><div id="article_content"  csdn-tracking-statistics"="" data-mod="popu_519" data-dsm="post">                         <p>asio 协程中 yield</p><p><br /></p><p>(金庆的专栏 2017.12)<br /></p><p><br /></p><p>https://stackoverflow.com/questions/26127458/yielding-in-boost-asio-stackful-coroutine</p><p><br /></p><p>Asio spawn() 可以产生一个协程，协程中可以调用 async_read(..., yield), async_write(..., yield), 但是不知道如何主动释放控制权(yield)?</p><p><br /></p><div><span style="font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif;color:#242729;font-size:13px;background-color:#eff0f1;line-height:1.3;border:0px none;">asio::spawn(strand_, [this, self](asio::yield_context yield)</span></div><div><span style="font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif;color:#242729;font-size:13px;background-color:#eff0f1;line-height:1.3;border:0px none;">{</span></div><span style="font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif;color:#242729;font-size:13px;background-color:#eff0f1;line-height:1.3;border:0px none;">&nbsp;&nbsp;&nbsp; while (!computationFinished)</span><div><span style="font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif;color:#242729;font-size:13px;background-color:#eff0f1;line-height:1.3;border:0px none;">&nbsp;&nbsp;&nbsp; {</span></div><div><span style="font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif;color:#242729;font-size:13px;background-color:#eff0f1;line-height:1.3;border:0px none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; computeSomeMore();</span></div><div><span style="font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif;color:#242729;font-size:13px;background-color:#eff0f1;line-height:1.3;border:0px none;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; yield; // WHAT SHOULD THIS LINE BE?</span></div><div><span style="font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif;color:#242729;font-size:13px;background-color:#eff0f1;line-height:1.3;border:0px none;">&nbsp;&nbsp;&nbsp; }</span></div><div>}</div><p><br /></p><p>答案是：</p><p><span style="font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif;color:#242729;border:0px none;font-size:13px;overflow:auto;background-color:#eff0f1;line-height:1.3;">iosvc.post(yield);</span><br /></p><p><br /></p><p>其他还可以是</p><p><span style="font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif;color:#242729;border:0px none;font-size:13px;overflow:auto;background-color:#eff0f1;line-height:1.3;">iosvc.poll_one();</span></p><p><span style="font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif;color:#242729;border:0px none;font-size:13px;overflow:auto;background-color:#eff0f1;line-height:1.3;">iosvc.poll();</span></p><p><span style="font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif;color:#242729;border:0px none;font-size:13px;overflow:auto;background-color:#eff0f1;line-height:1.3;"><br /></span></p><p>应该是 post(yield) 最合适。</p><p><br /></p><p><span style="font-family:Arial, 'Helvetica Neue', Helvetica, sans-serif;color:#242729;border:0px none;font-size:13px;line-height:1.3;">... polling the <span style="font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif;color:#242729;border:0px none;font-size:13px;background-color:#eff0f1;line-height:1.3;white-space:normal;">io_service</span> <span style="font-family:Arial, 'Helvetica Neue', Helvetica, sans-serif;color:#242729;border:0px none;font-size:13px;background-color:#ffffff;line-height:1.3;">avoids the context switch overhead, but unhandled exceptions from handlers will unwind and destroy the coroutine.</span></span><br /></p><p><br /></p>                    </div></div><img src ="http://www.cppblog.com/jinq0123/aggbug/215397.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2017-12-07 14:51 <a href="http://www.cppblog.com/jinq0123/archive/2017/12/07/215397.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Lua和C++之间调用效率测试</title><link>http://www.cppblog.com/jinq0123/archive/2017/08/30/215209.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 30 Aug 2017 09:25:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2017/08/30/215209.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/215209.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2017/08/30/215209.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/215209.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/215209.html</trackback:ping><description><![CDATA[<div>Lua和C++之间调用效率测试<br /><br />(金庆的专栏 2017.8)<br /><br />仿照 http://www.cnblogs.com/archy_yu/p/3185608.html 对 Lua 和 C++ 调用进行测试。<br /><br />代码见：https://github.com/jinq0123/TimerLuaIntf<br /><br />使用 LuaIntf 绑定 Lua 和 C++。用 boost timer 计时。<br />依赖库 lua-cpp, lua-intf, boost-timer 用 conan 安装。<br />conan 会下载源码，编译，然后生成 conanbuildinfo.props 给 VS 导入，<br />其中设好了所有 include, lib 目录，链接库，运行库。<br /><br />代码大概如下：<br /><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;cout &lt;&lt; "C++ calls lua add() many times:\n";</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;boost::timer::auto_cpu_timer t;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for (int i = 0; i &lt; COUNT; ++i)</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;test.dispatchStatic("add", 123, 456);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;}</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;cout &lt;&lt; "C++ calls lua add_times() once:\n";</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;boost::timer::auto_cpu_timer t;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;test.dispatchStatic("add_times", 123, 456, COUNT);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;}</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;cout &lt;&lt; "Lua calls C++ add() many times:\n";</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;boost::timer::auto_cpu_timer t;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;test.dispatchStatic("test_c_add", 123, 456, COUNT);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;}</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;cout &lt;&lt; "Lua calls C++ add_times() once:\n";</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;boost::timer::auto_cpu_timer t;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;test.dispatchStatic("test_c_add_times", 123, 456, COUNT);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;}</span><br /><br />测试4种调用：<br />* C++ 调用 1kw 次 lua add()<br />* C++ 调用 1 次 lua add_times(), 其中调用 add() 1kw 次<br />* Lua 调用 C++ add() 1kw 次<br />* Lua 调用 C++ add_times() 1 次，其中调用 add() 1kw 次<br /><br />输出如：<br /><span style="color: #0000ff;">C++ calls lua add() many times:</span><br /><span style="color: #0000ff;">&nbsp;2.759473s wall, 2.761218s user + 0.000000s system = 2.761218s CPU (100.1%)</span><br /><span style="color: #0000ff;">C++ calls lua add_times() once:</span><br /><span style="color: #0000ff;">&nbsp;0.436400s wall, 0.436803s user + 0.000000s system = 0.436803s CPU (100.1%)</span><br /><span style="color: #0000ff;">Lua calls C++ add() many times:</span><br /><span style="color: #0000ff;">&nbsp;0.535802s wall, 0.530403s user + 0.000000s system = 0.530403s CPU (99.0%)</span><br /><span style="color: #0000ff;">Lua calls C++ add_times() once:</span><br /><span style="color: #0000ff;">&nbsp;0.000005s wall, 0.000000s user + 0.000000s system = 0.000000s CPU (n/a%)</span><br />&nbsp;<br />结论是：<br />* C++ 调用 Lua 可达 3百万次/s<br />* Lua 内部调用函数可达 2千万次强/s<br />* Lua 调用 C++ 函数可达 2千万次弱/s<br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/215209.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2017-08-30 17:25 <a href="http://www.cppblog.com/jinq0123/archive/2017/08/30/215209.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>conan-transit服上的库列表</title><link>http://www.cppblog.com/jinq0123/archive/2017/08/05/215141.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sat, 05 Aug 2017 05:14:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2017/08/05/215141.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/215141.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2017/08/05/215141.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/215141.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/215141.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: conan-transit服上的库列表因为获取列表比较慢，所以获取后在此记录，以备查找。conan-transit 是个只读库，不会有更新。新的库将上传到 conan-center. conan是C/C++包管理器。conan search --remote conan-transitExisting package recipes:7z_installer/0.1@lasote/testingA...&nbsp;&nbsp;<a href='http://www.cppblog.com/jinq0123/archive/2017/08/05/215141.html'>阅读全文</a><img src ="http://www.cppblog.com/jinq0123/aggbug/215141.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2017-08-05 13:14 <a href="http://www.cppblog.com/jinq0123/archive/2017/08/05/215141.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Premake 生成 Makefile 的缺省配置</title><link>http://www.cppblog.com/jinq0123/archive/2017/07/31/215133.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Mon, 31 Jul 2017 07:00:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2017/07/31/215133.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/215133.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2017/07/31/215133.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/215133.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/215133.html</trackback:ping><description><![CDATA[<div>Premake 生成 Makefile 的缺省配置<br /><br />(金庆的专栏 2017.7)<br /><br /><span style="color:#000099;"><span style="background-color: #ffffff;">premake5.exe --os=linux gmake</span></span><br /><br />生成的 Makefile 中有个 config, 用 make 生成release版本时使用以下命令:<br /><br /><span style="color:#000099;">make config=release_x64</span><br /><br />在premake5.lua中可以如下设置，使config缺省为 release_x64：<br /><br /><span style="color:#660000;">workspace "AppWorkspace"<br />&nbsp;&nbsp; &nbsp;configurations { "Release", "Debug" }<br />&nbsp;&nbsp; &nbsp;platforms { "x64", "x32" }<br />&nbsp;&nbsp; &nbsp;...<br /></span><br />即缺省配置为 configurations 和 platforms 的首个选项。<br /><br />生成的 Makefile 中会如下初始化 config:<br /><br /><span style="color:#660000;">ifndef config<br />&nbsp; config=release_x64<br />endif<br /></span><br />这样 make 就会缺省生成 release_x64。</div><img src ="http://www.cppblog.com/jinq0123/aggbug/215133.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2017-07-31 15:00 <a href="http://www.cppblog.com/jinq0123/archive/2017/07/31/215133.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC6工程因行尾格式无法转换到VS2015</title><link>http://www.cppblog.com/jinq0123/archive/2017/06/07/214981.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 07 Jun 2017 02:22:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2017/06/07/214981.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214981.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2017/06/07/214981.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214981.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214981.html</trackback:ping><description><![CDATA[<div>VC6工程因行尾格式无法转换到VS2015<br /><br />(金庆的专栏 2017.6)<br /><br />参考：<br />https://connect.microsoft.com/VisualStudio/feedback/details/546432/problems-with-vs2010rc-doing-conversion-of-vs6-dsp-file-vcproj-file<br /><br />apr<br />&nbsp;消息 <br />&nbsp;apr.dsp: 无法转换项目。请确保这是一个有效的 Visual C++ 6.0 项目。 <br />&nbsp;apr.dsp: 项目升级失败。 <br />&nbsp;apr.dsp: 转换项目文件&#8220;E:\temp\apr-1.5.2\apr-1.5.2\apr.dsp&#8221;。 <br /><br />原来下载的是 zip 包可以正常转换升级。<br />现在下载了 bz 压缩包，解开后是Unix格式，所以出现无法转换。<br />转成Windows格式后就可以了。<br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214981.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2017-06-07 10:22 <a href="http://www.cppblog.com/jinq0123/archive/2017/06/07/214981.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> std::hash实现太简单分布不匀</title><link>http://www.cppblog.com/jinq0123/archive/2017/05/26/214959.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Fri, 26 May 2017 04:00:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2017/05/26/214959.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214959.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2017/05/26/214959.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214959.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214959.html</trackback:ping><description><![CDATA[<div><div id="article_content"  tracking-ad"="" data-mod="popu_307" data-dsm="post"> std::hash实现太简单分布不匀<br /><br />(金庆的专栏 2017.5)<br /><br /><span style="font-family:Courier New;"><span style="color:#990000;">#include &lt;iostream&gt;<br />#include &lt;functional&gt;<br /><br />using namespace std;<br /><br />int main()<br />{<br />&nbsp;&nbsp;&nbsp; std::hash&lt;int&gt; hasher;<br />&nbsp;&nbsp;&nbsp; cout &lt;&lt; hasher(2) &lt;&lt; endl;<br />&nbsp;&nbsp;&nbsp; cout &lt;&lt; hasher(3) &lt;&lt; endl;<br />&nbsp;&nbsp;&nbsp; cout &lt;&lt; hasher(4) &lt;&lt; endl;<br /><br />&nbsp;&nbsp;&nbsp; return 0;<br />}</span><br /></span><br />输出为<br /><span style="font-family:Courier New;color:#000066;">jinqing@server:~/test$ g++ main.cpp -std=c++11<br />jinqing@server:~/test$ ./a.out<br />2<br />3<br />4<br /></span><br />查看实现，/usr/include/c++/5/bits/functional_hash.h<br /><br /><span style="font-family:Courier New;color:#990000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; operator()(_Tp __val) const noexcept&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { return static_cast&lt;size_t&gt;(__val); }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<br /></span><br />所以对分布有要求的，应该使用自己的hash, 不要使用 std::hash.<br /><br />boost::hash 的实现也是简单取值，<br />boost_1_60_0/boost/functional/hash/hash.hpp<br /><br /><span style="font-family:Courier New;color:#990000;">&nbsp;&nbsp;&nbsp; template &lt;typename T&gt;<br />&nbsp;&nbsp;&nbsp; typename boost::hash_detail::basic_numbers&lt;T&gt;::type hash_value(T v)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return static_cast&lt;std::size_t&gt;(v);<br />&nbsp;&nbsp;&nbsp; }<br /></span><br />Boost说明了hash用于STL容器，而不是其它。<br />&nbsp;&nbsp;  &nbsp;This hash function is designed to be used in containers based on the  STL and is not suitable as a general purpose hash function. <br />&nbsp;&nbsp; &nbsp;<br />VS2015会使用 FNV-1a<br /><br /><span style="font-family:Courier New;color:#990000;">&nbsp;&nbsp; &nbsp;size_t operator()(const argument_type&amp; _Keyval) const<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp; &nbsp;// hash _Keyval to size_t value by pseudorandomizing transform<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return (_Hash_seq((const unsigned char *)_Keyval.c_str(),<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;_Keyval.size() * sizeof (_Elem)));<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}</span><br /><br /><span style="font-family:Courier New;color:#990000;">&nbsp;&nbsp; &nbsp;inline size_t _Hash_seq(const unsigned char *_First, size_t _Count)<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp; &nbsp;// FNV-1a hash function for bytes in [_First, _First + _Count)<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;...</span><br /><br />但 FNV-1a 也不是通用的 hash 函数，如果输入值相近，则其输出值也相近。<br /> </div></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214959.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2017-05-26 12:00 <a href="http://www.cppblog.com/jinq0123/archive/2017/05/26/214959.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用preload加载Lua导出模块</title><link>http://www.cppblog.com/jinq0123/archive/2017/05/10/214923.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 10 May 2017 08:11:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2017/05/10/214923.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214923.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2017/05/10/214923.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214923.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214923.html</trackback:ping><description><![CDATA[<div><div id="article_content"> 用preload加载Lua导出模块<br /><br />(金庆的专栏 2017.5)<br /><br />参考：<br />How to make exported module non-global?<br />https://github.com/SteveKChiu/lua-intf/issues/135<br /><br />动态库可以这样导出模块：<br /><br /><span style="font-family:Courier New;color:#660000;">&nbsp;&nbsp;&nbsp; extern "C"<br />&nbsp;&nbsp;&nbsp; #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__)<br />&nbsp;&nbsp;&nbsp; __declspec(dllexport)<br />&nbsp;&nbsp;&nbsp; #endif<br />&nbsp;&nbsp;&nbsp; int luaopen_modname(lua_State* L)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LuaRef mod = LuaRef::createTable(L);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LuaBinding(mod)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mod.pushToStack();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<br />&nbsp;&nbsp;&nbsp; }<br /></span><br />如果不是动态库，可以这样导出全局模块 c_util：<br /><br /><span style="font-family:Courier New;color:#660000;">int main()<br />{<br />&nbsp;&nbsp; &nbsp;...<br />&nbsp;&nbsp; &nbsp;LuaBinding(L).beginModule("c_util")<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.addFunction("foo", []() { return 123; })<br />&nbsp;&nbsp; &nbsp;.endModule();<br />&nbsp;&nbsp; &nbsp;...<br />}<br /></span><br />如果不想让它成为全局模块，则需要在 package.preload 表中注册一个加载函数.<br /><br />Lua程序设计 第3版 英文版 programming in lua 3ed<br /><br /><span style="color:#666666;"><span style="background-color: #ffffff;">The preload searcher allows the definition of an arbitrary function to load a module. <br />It uses a table, called package.preload, to map module names to loader functions. <br />When searching for a module name, this searcher simply looks for the given name in the table. <br />If it finds a function there, it returns this function as the module loader. <br />Otherwise, it returns nil. <br />This searcher provides a generic method to handle some non-conventional situations. <br />For instance, a C library statically linked to Lua can register its luaopen_ function into the preload table,<br />so that it will be called only when (and if) the user requires that module. <br />In this way, the program does not waste time opening the module if it is not used.<br /></span></span><br />代码示例：<br /><br /><span style="font-family:Courier New;color:#660000;">&nbsp;&nbsp;&nbsp; extern "C" int open_my_module(lua_State* L)<br />&nbsp;&nbsp;&nbsp; {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LuaRef mod = LuaRef::createTable(L);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LuaBinding(mod)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .addFunction("get_my_svr_id", &amp;Util::GetMySvrId)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mod.pushToStack();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<br />&nbsp;&nbsp;&nbsp; }<br /><br />&nbsp;&nbsp; &nbsp;int main()<br />&nbsp;&nbsp; &nbsp;{<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;...<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;LuaRef table(L, "package.preload");<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;table["c_util"] = LuaRef::createFunctionWith(L, open_my_module);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;...<br />&nbsp;&nbsp; &nbsp;}<br /></span><br />Lua 测试：<br /><span style="font-family:Courier New;color:#660000;">&nbsp;&nbsp; &nbsp;assert(c_util == nil)<br />&nbsp;&nbsp; &nbsp;local t = require("c_util")<br />&nbsp;&nbsp; &nbsp;assert("table" == type(t))<br />&nbsp;&nbsp; &nbsp;assert("function" == type(t.get_my_svr_id))<br /></span><br />    </div>                                                                         </div><img src ="http://www.cppblog.com/jinq0123/aggbug/214923.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2017-05-10 16:11 <a href="http://www.cppblog.com/jinq0123/archive/2017/05/10/214923.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>grpc++不支持异步多次写入</title><link>http://www.cppblog.com/jinq0123/archive/2017/05/07/214914.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 07 May 2017 02:38:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2017/05/07/214914.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214914.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2017/05/07/214914.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214914.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214914.html</trackback:ping><description><![CDATA[<div><p>grpc++不支持异步多次写入</p><p><br /></p><p>(金庆的专栏 2017.5)</p><p><br /></p>见：<br /><br />Multi ClientAsyncWriter::Write() calls will crash. #7659<br />https://github.com/grpc/grpc/issues/7659<br /><br />why the continuous write to async streaming crash? #4007<br />https://github.com/grpc/grpc/issues/4007<br /><br />write stream error:GRPC_CALL_ERROR_ALREADY_INVOKED <br />https://github.com/grpc/grpc/issues/3953<br /><br />grpc_cb 支持真正的异步写。<br />https://github.com/jinq0123/grpc_cb</div><img src ="http://www.cppblog.com/jinq0123/aggbug/214914.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2017-05-07 10:38 <a href="http://www.cppblog.com/jinq0123/archive/2017/05/07/214914.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>支持 proto3 的 lua 绑定库 LuaPbIntf</title><link>http://www.cppblog.com/jinq0123/archive/2017/04/25/214883.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Tue, 25 Apr 2017 03:43:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2017/04/25/214883.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214883.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2017/04/25/214883.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214883.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214883.html</trackback:ping><description><![CDATA[<div>支持 proto3 的 lua 绑定库 <a href="https://github.com/jinq0123/LuaPbIntf">LuaPbIntf</a><br /><br />(金庆的专栏 2017.4)<br /><br />protobuf的lua绑定库之前一直用 pbc，但是该库已经不更新了。<br />想要添加 proto3 的 map , 还有支持 service, 发现代码太高深，无法下手。<br /><br />pbc因为用c代码实现了 protobuf 的功能，所以代码量很大。<br />而对于 c++ 来说，只需要利用 protobuf 库中动态消息就可以实现 lua 所需功能。<br /><br />luapb 就是直接用 protobuf 库封装后导出lua实现的。该库仅支持 proto2.<br /><br />在 luapb 基础上实现对 proto3 的支持，就是 <a href="https://github.com/jinq0123/LuaPbIntf">LuaPbIntf </a>库。<br />LuaPbIntf 库利用了 lua-intf 库来实现 c++ 与 lua 绑定，所以代码量比 luapb 又少了许多，<br />并且可读性大大增强，更改添加新功能也就更方便了。<br /><br />与 pbc, lubpb 一样，LuaPbIntf 也是动态加载 proto 文件，不需要代码生成。<br /><br />LuaPbIntf 采用 lua table 来表示 pb 消息，不是 pbc 中的代理表，而只是普通表。<br /><br />项目地址：<a href="https://github.com/jinq0123/LuaPbIntf">https://github.com/jinq0123/LuaPbIntf</a><br /><br />示例：<br /><br /><span style="color: #800000; font-family: Courier;">local pb = require("luapbintf")</span><br /><br /><span style="color: #800000; font-family: Courier;">pb.import_proto_file("test.proto")</span><br /><br /><span style="color: #800000; font-family: Courier;">local msg = { uid = 12345 }</span><br /><span style="color: #800000; font-family: Courier;">local sz = pb.encode("test.TestMsg", msg)</span><br /><br /><span style="color: #800000; font-family: Courier;">local msg2 = pb.decode("test.TestMsg", sz)</span><br /><span style="color: #800000; font-family: Courier;">assert(msg2.uid == 12345)</span><br /><br />proto3 map 示例：<br /><br /><span style="color: #800000; font-family: Courier;">local msgs = {}</span><br /><span style="color: #800000; font-family: Courier;">msgs["k1"] = {}</span><br /><span style="color: #800000; font-family: Courier;">msgs["k2"] = {}</span><br /><span style="color: #800000; font-family: Courier;">pb.encode("test.TestMsg", { msgs = msgs })</span><br /><br />rpc service 支持:<br /><br /><span style="color: #800000; font-family: Courier;">assert(pb.get_rpc_input_name("test.Test", "Foo") == "test.TestMsg")</span><br /><span style="color: #800000; font-family: Courier;">assert(pb.get_rpc_output_name("test.Test", "Foo") == "test.CommonMsg")</span><br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214883.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2017-04-25 11:43 <a href="http://www.cppblog.com/jinq0123/archive/2017/04/25/214883.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>建议proto文件按包名分子目录</title><link>http://www.cppblog.com/jinq0123/archive/2017/04/17/214862.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Mon, 17 Apr 2017 06:40:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2017/04/17/214862.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214862.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2017/04/17/214862.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214862.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214862.html</trackback:ping><description><![CDATA[<div>建议proto文件按包名分子目录<br /><br />(金庆的专栏 2017.4)<br /><br />服务器客户端之间的protobuf协议定义在客户端与服务器公共目录下，包名为rpc.<br />服务器内部协议定义在服务器目录下，包名为svr.<br />rpc.EmptyMsg 和 svr.EmptyMsg 分别定义在各自的根目录，文件名都是 empty_msg.proto.<br />运行时就会报错：<br /><br /><span style="color: #0000ff;">[libprotobuf ERROR E:\deps\protobuf-3.2.0\protobuf-3.2.0\src\google\protobuf\</span><br /><span style="color: #0000ff;">descriptor_database.cc:57] File already exists in database : empty_msg.proto</span><br /><span style="color: #0000ff;">[libprotobuf FATAL E:\deps\protobuf-3.2.0\protobuf-3.2.0\src\google\protobuf\</span><br /><span style="color: #0000ff;">descriptor.cc:1275] CHECK failed: generated_database_-&gt;Add(encoded_file_descriptor, size):</span><br /><br />原因为试图用同一个文件名"empty_msg.proto"往descriptor_database添加descriptor。<br /><br />如果按包名分子目录，文件名就可以分开为 "rpc/empty_msg.proto" 和 "svr/empty_msg.proto".<br /><br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214862.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2017-04-17 14:40 <a href="http://www.cppblog.com/jinq0123/archive/2017/04/17/214862.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>behaviac动态库运行出错</title><link>http://www.cppblog.com/jinq0123/archive/2017/03/16/214755.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 16 Mar 2017 03:40:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2017/03/16/214755.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214755.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2017/03/16/214755.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214755.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214755.html</trackback:ping><description><![CDATA[<div>behaviac动态库运行出错<br /><br />(金庆的专栏 2017.3.16)<br /><br />游戏是静态链接的运行库，添加behaviac动态库后，运行出错：<br /><br />&gt;&nbsp;&nbsp; &nbsp;ucrtbased.dll!free_dbg_nolock(void * const block, const int block_use) 行 996&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;ucrtbased.dll!_free_dbg(void * block, int block_use) 行 1030&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;libbehaviac_msvc_debug.dll!operator delete(void * block) 行 17&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;libbehaviac_msvc_debug.dll!std::_Deallocate(void * _Ptr, unsigned int _Count, unsigned int _Sz) 行 132&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;libbehaviac_msvc_debug.dll!std::allocator&lt;std::_Container_proxy&gt;::deallocate(std::_Container_proxy * _Ptr, unsigned int _Count) 行 720&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;libbehaviac_msvc_debug.dll!std::_Wrap_alloc&lt;std::allocator&lt;std::_Container_proxy&gt; &gt;::deallocate(std::_Container_proxy * _Ptr, unsigned int _Count) 行 988&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;libbehaviac_msvc_debug.dll!std::_String_alloc&lt;std::_String_base_types&lt;char,std::allocator&lt;char&gt; &gt; &gt;::_Free_proxy() 行 661&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;libbehaviac_msvc_debug.dll!std::_String_alloc&lt;std::_String_base_types&lt;char,std::allocator&lt;char&gt; &gt; &gt;::~_String_alloc&lt;std::_String_base_types&lt;char,std::allocator&lt;char&gt; &gt; &gt;() 行 629&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;libbehaviac_msvc_debug.dll!std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt;::~basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt;() 行 1018&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;libbehaviac_msvc_debug.dll!behaviac::CTagObject::Save(behaviac::IIONode * node, const char * szClassName) 行 100&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;libbehaviac_msvc_debug.dll!behaviac::Agent::InitVariableRegistry() 行 476&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;libbehaviac_msvc_debug.dll!behaviac::Agent::Init_(int contextId, behaviac::Agent * pAgent, short priority, const char * agentInstanceName) 行 227&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;giant_test_client.exe!behaviac::Agent::InitAgent(behaviac::Agent * pAgent, const char * agentInstanceName, const char * agentInstanceNameAny, bool bToBind, int contextId, short priority) 行 56&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;giant_test_client.exe!behaviac::Agent::Create&lt;PlaneAgent&gt;(const char * agentInstanceName, int contextId, short priority) 行 88&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;giant_test_client.exe!Client::InitPlayer() 行 36&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;giant_test_client.exe!Client::Client() 行 23&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;giant_test_client.exe!main() 行 50&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;giant_test_client.exe!invoke_main() 行 64&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;giant_test_client.exe!__scrt_common_main_seh() 行 253&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;giant_test_client.exe!__scrt_common_main() 行 296&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;giant_test_client.exe!mainCRTStartup() 行 17&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;kernel32.dll!@BaseThreadInitThunk@12()&nbsp;&nbsp; &nbsp;未知<br />&nbsp;&nbsp;&nbsp; &nbsp;ntdll.dll!___RtlUserThreadStart@8()&nbsp;&nbsp; &nbsp;未知<br />&nbsp;&nbsp;&nbsp; &nbsp;ntdll.dll!__RtlUserThreadStart@8()&nbsp;&nbsp; &nbsp;未知<br /><br />看来是string跨越动态库析构。<br />如果string在动态库中构造又析构，动态库的运行时库可以与主程序不同。<br />但如果用主程序的运行时申请内存，在动态库中用另一个运行时库释放，就会产生上面的错误。<br /><br />可以建立一个最小化的程序来复现上面的错误。<br />新建一个行为树，为Agent创建一个属性。<br />然后主程序运行库设为：多线程调试 (/MTd)，而不是：多线程调试 DLL (/MDd)。<br />调试运行创建Agent时就会出上面错误。 <br /><br />疑问是这是动态库内部调用，怎么会产生跨库析构呢？<br /><br />断点进入string的构造过程可以发现，string不是动态库构造的，而是主程序构造的：<br /><br />&gt;&nbsp;&nbsp; &nbsp;test_client.exe!behaviac::StringUtils::internal::ToString(const std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt; &amp; val) 行 138&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!behaviac::StringUtils::Detail::ToStringPtrHanler&lt;std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt;,0&gt;::ToString(const std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt; &amp; v) 行 192&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!behaviac::StringUtils::Detail::ToStringEnumHanler&lt;std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt;,0&gt;::ToString(const std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt; &amp; v) 行 228&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!behaviac::StringUtils::Detail::ToStringStructHanler&lt;std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt;,0&gt;::ToString(const std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt; &amp; val) 行 242&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!behaviac::StringUtils::ToString&lt;std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt; &gt;(const std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt; &amp; val) 行 256&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!behaviac::SetFromString_t&lt;std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt;,0&gt;::Get(std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt; &amp; value) 行 790&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!behaviac::CProperty&lt;std::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt; &gt; &gt;::GetValueToString(const behaviac::Agent * self) 行 848&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;libbehaviac_msvc_debug.dll!behaviac::CTagObject::Save(behaviac::IIONode * node, const char * szClassName) 行 97&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;libbehaviac_msvc_debug.dll!behaviac::Agent::InitVariableRegistry() 行 476&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;libbehaviac_msvc_debug.dll!behaviac::Agent::Init_(int contextId, behaviac::Agent * pAgent, short priority, const char * agentInstanceName) 行 227&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!behaviac::Agent::InitAgent(behaviac::Agent * pAgent, const char * agentInstanceName, const char * agentInstanceNameAny, bool bToBind, int contextId, short priority) 行 56&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!behaviac::Agent::Create&lt;PlaneAgent&gt;(const char * agentInstanceName, int contextId, short priority) 行 88&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!Client::InitPlayer() 行 36&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!Client::Client() 行 23&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!main() 行 50&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!invoke_main() 行 64&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!__scrt_common_main_seh() 行 253&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!__scrt_common_main() 行 296&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;test_client.exe!mainCRTStartup() 行 17&nbsp;&nbsp; &nbsp;C++<br />&nbsp;&nbsp;&nbsp; &nbsp;kernel32.dll!75c3336a()&nbsp;&nbsp; &nbsp;未知<br />&nbsp;&nbsp;&nbsp; &nbsp;[下面的框架可能不正确和/或缺失，没有为 kernel32.dll 加载符号]&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; &nbsp;ntdll.dll!76fa9902()&nbsp;&nbsp; &nbsp;未知<br />&nbsp;&nbsp;&nbsp; &nbsp;ntdll.dll!76fa98d5()&nbsp;&nbsp; &nbsp;未知<br /><br />原因为 IProperty::GetValueToString()是虚函数，实际实现是由主程序实现模板类。<br />&nbsp;&nbsp; &nbsp;behaviac::CProperty&lt;&gt;::GetValueToString()<br /><br />解决方案为使用behaviac静态库并且静态链接运行时库。<br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214755.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2017-03-16 11:40 <a href="http://www.cppblog.com/jinq0123/archive/2017/03/16/214755.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Lua53 premake</title><link>http://www.cppblog.com/jinq0123/archive/2017/02/18/214686.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sat, 18 Feb 2017 14:18:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2017/02/18/214686.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214686.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2017/02/18/214686.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214686.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214686.html</trackback:ping><description><![CDATA[<div>Lua53 premake<br /><br />(金庆的专栏 2017.2)<br /><br />参考：用premake5创建lua532工程 <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://blog.csdn.net/jq0123/article/details/51242780<br /><br /><span style="color: #800000; font-family: Courier;">-- premake5.lua</span><br /><span style="color: #800000; font-family: Courier;">--[[</span><br /><span style="color: #800000; font-family: Courier;">Usage examples: </span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; for windows: premake5.exe --os=windows vs2015</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; fot linux:&nbsp;&nbsp; premake5.exe --os=linux gmake</span><br /><span style="color: #800000; font-family: Courier;">]]</span><br /><br /><span style="color: #800000; font-family: Courier;">workspace "lua53"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; configurations { "Debug", "Release" }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; targetdir "bin/%{cfg.buildcfg}"</span><br /><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; language "C++"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; -- Force VS to compile as C++.</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; -- https://github.com/premake/premake-core/issues/142</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; filter "action:vs*"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; buildoptions "/TP"</span><br /><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; filter "system:windows"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; defines { "LUA_BUILD_AS_DLL" }</span><br /><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; filter "configurations:Debug"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; defines { "DEBUG" }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; flags { "Symbols" }</span><br /><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; filter "configurations:Release"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; defines { "NDEBUG" }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; optimize "On"</span><br /><br /><span style="color: #800000; font-family: Courier;">project "lua53"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; kind "ConsoleApp"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; files { "src/lua.c" }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; links { "lua53_shared_lib" }&nbsp; &nbsp;</span><br /><br /><span style="color: #800000; font-family: Courier;">project "luac53"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; kind "ConsoleApp"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; files { "src/luac.c" }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; links { "lua53_static_lib" }&nbsp; -- Link error on Windows if link lua53 shared lib.&nbsp; &nbsp;</span><br /><br /><span style="color: #800000; font-family: Courier;">project "lua53_shared_lib"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; kind "SharedLib"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; targetname "lua53"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; files { "src/*.h", "src/*.c" }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; removefiles { "src/lua.c", "src/luac.c" }</span><br /><br /><span style="color: #800000; font-family: Courier;">project "lua53_static_lib"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; kind "StaticLib"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; targetname "lua53"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; filter "system:windows"</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; targetprefix "lib"&nbsp; -- liblua53.lib<br />&nbsp;&nbsp; filter {}<br /></span><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; files { "src/*.h", "src/*.c" }</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; removefiles { "src/lua.c", "src/luac.c" }</span><br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />更改之处：<br />* VS强制按C++编译<br />* 创建动态库和静态库<br />* lua53.exe 链接动态库，luac53.exe 链接静态库<br /><div>&nbsp; 因为 luac53.exe 链接动态库缺3个函数未导出。<br />* 添加宏 LUA_BUILD_AS_DLL，不然 lua53.dll 不会生成 lua53.lib&nbsp; &nbsp;</div>&nbsp;</div><img src ="http://www.cppblog.com/jinq0123/aggbug/214686.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2017-02-18 22:18 <a href="http://www.cppblog.com/jinq0123/archive/2017/02/18/214686.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用grpc_cb代替grpc++</title><link>http://www.cppblog.com/jinq0123/archive/2017/01/22/214626.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Sun, 22 Jan 2017 10:06:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2017/01/22/214626.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214626.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2017/01/22/214626.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214626.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214626.html</trackback:ping><description><![CDATA[<div><h1>用grpc_cb代替grpc++</h1>  <p>(金庆的专栏 2017.1)</p>  <p><a href="https://github.com/jinq0123/grpc_cb">jinq0123/grpc_cb</a> <br /> 是 Google <a href="https://github.com/grpc/grpc">gRpc</a> 的C++库。 <br /> 它依赖于 grpc, 采用回调接口，简化了使用，用来代替 grpc++ 库。</p>  <p>使用简介如下。</p>    <h2>定义服务</h2>  <p>用 proto 文件定义服务：</p><p>&nbsp;</p><div><span style="color: #800000;">// See examples/protos/route_guide.proto.</span><br /><br /><span style="color: #800000;">syntax = "proto3";</span><br /><br /><span style="color: #800000;">package routeguide;</span><br /><br /><span style="color: #800000;">// Interface exported by the server.</span><br /><span style="color: #800000;">service RouteGuide {</span><br /><span style="color: #800000;">&nbsp; // A simple RPC.</span><br /><span style="color: #800000;">&nbsp; rpc GetFeature(Point) returns (Feature) {}</span><br /><span style="color: #800000;">}</span><br /><br /><span style="color: #800000;">message Point {</span><br /><span style="color: #800000;">&nbsp; int32 latitude = 1;</span><br /><span style="color: #800000;">&nbsp; int32 longitude = 2;</span><br /><span style="color: #800000;">}</span><br /><br /><span style="color: #800000;">message Feature {</span><br /><span style="color: #800000;">&nbsp; string name = 1;</span><br /><span style="color: #800000;">&nbsp; Point location = 2;</span><br /><span style="color: #800000;">}</span><br /></div>生成服务器和客户端代码<p>&nbsp;</p><div>详见：examples/protos/generate.bat<br /><br /><span style="color: #000080;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;protoc.exe -I . --cpp_out=../cpp_cb/route_guide route_guide.proto</span><br /><span style="color: #000080;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;protoc.exe -I . --grpc_out=../cpp_cb/route_guide --plugin=protoc-gen-grpc=grpc_cpp_cb_plugin.exe route_guide.proto</span><br /></div><code></code>在examples/cpp_cb/route_guide/ 生成以下文件:  <ul><li><code>route_guide.pb.h</code>, 消息类定义</li><li><code>route_guide.pb.cc</code>, 消息类实现</li><li><code>route_guide.grpc_cb.pb.h</code>, 服务类定义</li><li><code>route_guide.grpc_cb.pb.cc</code>, 服务类实现</li></ul>  <p>生成的命名空间<code>RouteGuide</code>将包含</p>  <ul><li>客户端使用的<code>Stub</code>类.</li><li>需服务器实现的<code>Service</code>类.</li></ul>    <h2>客户端调用RPC</h2>    <h3>同步调用</h3>    <pre name="code"><code hljs=""  has-numbering"=""></code><div><span style="color: #800000;">ChannelSptr channel(new Channel("localhost:50051"));</span><br /><span style="color: #800000;">Stub stub(channel);</span><br /><br /><span style="color: #800000;">Point point = MakePoint(0, 0);</span><br /><span style="color: #800000;">Feature feature;</span><br /><span style="color: #800000;">Status status = stub.BlockingGetFeature(point, &amp;feature);</span></div><br /></pre>  <h3>异步调用</h3>    <pre name="code"><code hljs=""  has-numbering"=""><div><span style="color: #800000;">stub.AsyncGetFeature(point,</span><br /><span style="color: #800000;">	[](const Feature&amp; feature) {</span><br /><span style="color: #800000;">		cout &lt;&lt; feature.name() &lt;&lt; endl;</span><br /><span style="color: #800000;">	});</span><br /></div></code></pre>  <h2>服务器实现</h2><p>先实现服务类</p><div><span style="color: #800000;">&nbsp;&nbsp;&nbsp; class RouteGuideImpl final : public routeguide::RouteGuide::Service {</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;public:</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;void GetFeature(const Point&amp; point,</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;const GetFeature_Replier&amp; replier) override {</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Feature feature;</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;feature.set_name("...");</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;replier.Reply(feature);</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}&nbsp;&nbsp; &nbsp;</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;}</span></div><pre name="code"><code>GetFeature()</code>不必立即应答，可复制保存replier后直接返回， 待应答内容准备完成后，再调用<code>Reply()</code>.<br /><br />开启服务</pre></div><div><span style="color: #800000;">&nbsp;&nbsp;&nbsp; Server svr;</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;svr.AddListeningPort("0.0.0.0:50051");</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;RouteGuideImpl service(db_path);</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;svr.RegisterService(service);</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;svr.BlockingRun();</span><br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214626.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2017-01-22 18:06 <a href="http://www.cppblog.com/jinq0123/archive/2017/01/22/214626.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hiredis异步接口封装并导出到Lua</title><link>http://www.cppblog.com/jinq0123/archive/2017/01/05/214574.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 05 Jan 2017 10:42:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2017/01/05/214574.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214574.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2017/01/05/214574.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214574.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214574.html</trackback:ping><description><![CDATA[<div>hiredis异步接口封装并导出到Lua<br /><br />(金庆的专栏 2017.1)<br /><br />hiredis 不支持 Windows, Windows 下使用 wasppdotorg / hiredis-for-windows 。<br />Linux 下仍是 redis/hiredis。<br />hiredis-for-windows 是以 hiredis 0.13.3 为基础移植的。<br /><br />hiredis-for-windows 需要稍加修正：<br />&nbsp;&nbsp; &nbsp;* 去除 inline 宏<br />&nbsp;&nbsp; &nbsp;* TCP_NODELAY 改在连接之前设置。<br />详见其Issue.<br /><br />Cluster 支持采用 shinberg/cpp-hiredis-cluster。这是个CPP库，支持异步，<br />要求 hiredis &gt;= 0.12.0。<br />jinq0123/cpp-hiredis-cluster 在 develop 分支上更改了接口，让它更好用。<br /><br />因为网络库是boost asio, 所以需要asio适配器，采用 jinq0123/hiredis-boostasio-adapter。<br /><br />cpp-hiredis-cluster 提供的是统一的Command接口，接收字符串命令，返回 redisReply.<br />对于常用命令，需要更简单的接口。<br />在Lua手游服务器代码中新建CRedis类，封装 cpp-hiredis-cluster，<br />为常用redis命令封装更好用的接口。<br />CRedis类封装了asio, 接口是根据应用需要定义的，所以是专用接口，<br />不在 cpp-hiredis-cluster 中实现。<br /><br /><span style="color: #800000; font-family: Courier;">bool CRedis::Init(io_service&amp; rIos, const std::string&amp; sHost, uint16_t uPort)</span><br />创建 RedisCluster 对象。<br />io_service 用于创建一个 redis 事件适配器，<br />RedisCluster创建需要一个适配器。<br />sHost, uPort 用于初始化连接redis cluster, 获取集群信息。<br /><br /><br /><span style="color: #800000; font-family: Courier;">using Cmd = RedisCluster::AsyncHiredisCommand;</span><br /><br /><span style="color: #800000; font-family: Courier;">bool CRedis::Init(io_service&amp; rIos, const std::string&amp; sHost, uint16_t uPort)</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;m_pAdapter.reset(new Adapter(rIos));</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;try</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;m_pCluster.reset(Cmd::createCluster("127.0.0.1", 7000, *m_pAdapter));</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;}</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;catch (const RedisCluster::ClusterException &amp;e)</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;LOG_ERROR("Cluster exception: " &lt;&lt; e.what());</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return false;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;}</span><br /><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;return true;</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">static Cmd::Action handleException(const RedisCluster::ClusterException &amp;exception,</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;RedisCluster::HiredisProcess::processState state)</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;// Check the exception type.</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;// Retry in case of non-critical exceptions.</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;if (!dynamic_cast&lt;const RedisCluster::CriticalException*&gt;(&amp;exception))</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;LOG_WARN("Exception in processing async redis callback: "</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;&lt; exception.what() &lt;&lt; " Retry...");</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;// retry to send a command to redis node</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return Cmd::RETRY;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;}</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;LOG_ERROR("Critical exception in processing async redis callback: "</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;&lt; exception.what());</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;return Cmd::FINISH;</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">static void handleSetReply(const redisReply &amp;reply, const CRedis::SetCb&amp; setCb)</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;if (!setCb) return;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;if (reply.type == REDIS_REPLY_STATUS)</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;const std::string OK("OK");</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (OK == reply.str)</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;setCb(true);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;}</span><br /><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;LOG_WARN("Set reply: " &lt;&lt; reply.str);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;setCb(false);</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">void CRedis::Set(const string&amp; sKey, const string&amp; sValue, const SetCb&amp; setCb)</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;assert(m_pCluster);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;Cmd::commandf2(*m_pCluster, sKey,</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;[setCb](const redisReply&amp; reply) {</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;handleSetReply(reply, setCb);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;},</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;handleException,</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"set %s %s", sKey.c_str(), sValue.c_str());</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">static void handleGetReply(const redisReply&amp; reply,</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;const CRedis::ReplyStringCb&amp; hdlStrReply)</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;if (!hdlStrReply) return;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;using Rt = CRedis::ReplyType;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;if (reply.type == REDIS_REPLY_NIL)</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;hdlStrReply(Rt::NIL, "");</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;}</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;std::string sReply(reply.str, reply.len);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;if (reply.type == REDIS_REPLY_STRING)</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;hdlStrReply(Rt::OK, sReply);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;else</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;hdlStrReply(Rt::ERR, sReply);</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">void CRedis::Get(const std::string&amp; sKey, const ReplyStringCb&amp; hdlStrRepl)</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;assert(m_pCluster);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;Cmd::commandf2(*m_pCluster, sKey,</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;[hdlStrRepl](const redisReply&amp; reply) {</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;handleGetReply(reply, hdlStrRepl);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;},</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;handleException,</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"get %s", sKey.c_str());</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br />handleException 是Cmd::command() 接口中需要的异常处理，这里是尽量重试。<br /><br />Cmd::command() 中的第3个参数是 redis 应答的回调，读取 redisReply, 然后触发命令的回调。<br /><br />CRedis::Get() 执行 redis GET 命令，固定1个参数，返回是字符串，nil, 或错误。<br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;enum class ReplyType</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;OK = 0,&nbsp; // redis replys string/integer/array</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;NIL = 1,&nbsp; // redis replys nil</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ERR = 2,&nbsp; // redis replys error status</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;};</span><br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;// 简单的常用命令会自动解析reply, 使用更易用的回调。</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;using ReplyStringCb = function&lt;void (ReplyType, const string&amp; sReply)&gt;;</span><br /><br />CRedis::Get() 的回调就是 ReplyStringCb。<br /><br />void CRedis::Set() 的回调只需知道成功或失败，SetCb 定义为：<br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;using SetCb = function&lt;void (bool ok)&gt;;</span><br /><br />失败时会有错误信息，已统一打印日志，不再暴露出来。<br /><br />SET 命令完整的参数列表还有其他参数：<br />set key value [EX seconds] [PX milliseconds] [NX|XX]<br /><br />因为常用的就 "set key value", 其他扩展的命令需要使用通用的 command() 接口，<br />并需要读取 redisReply.<br /><br />使用 LuaIntf 导出 CRedis 到 Lua.<br />因为只有一个 CRedis, 所以导出为模块 c_redis:<br /><br /><span style="color: #800000; font-family: Courier;">#include &lt;LuaIntf/LuaIntf.h&gt;</span><br /><br /><span style="color: #800000; font-family: Courier;">namespace {</span><br /><br /><span style="color: #800000; font-family: Courier;">void Set(const string&amp; sKey, const string&amp; sValue, const LuaRef&amp; luaSetCb)</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;// Default is empty callback.</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;auto setCb = ToFunction&lt;CRedis::SetCb&gt;(luaSetCb);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;GetRedis().Set(sKey, sValue, setCb);</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">void Get(const string&amp; sKey, const LuaRef&amp; luaReplyStringCb)</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;auto replyStringCb = ToFunction&lt;CRedis::ReplyStringCb&gt;(</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;luaReplyStringCb);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;GetRedis().Get(sKey, replyStringCb);</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br /><span style="color: #800000; font-family: Courier;">}&nbsp; // namespace</span><br /><br /><span style="color: #800000; font-family: Courier;">void Bind(lua_State* L)</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;LuaBinding(L).beginModule("c_redis")</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.addFunction("set", &amp;Set)</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.addFunction("get", &amp;Get)</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;.endModule();</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br />需要将 lua 的回调函数转成 cpp 的回调：<br /><br /><span style="color: #800000; font-family: Courier;">template &lt;class Function&gt;</span><br /><span style="color: #800000; font-family: Courier;">Function ToFunction(const LuaIntf::LuaRef&amp; luaFunction)</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;// Default is empty.</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;if (!luaFunction)</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return Function();&nbsp; // skip nil</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;if (luaFunction.isFunction())</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return luaFunction.toValue&lt;Function&gt;();&nbsp; // Todo: catch</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;LOG_WARN_TO("ToFunction", "Lua function expected, but got "</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;&lt; luaFunction.typeName());</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;return Function();</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br />Lua 这样调用：<br /><span style="color: #000080; font-family: Courier;">c_redis.set("FOO", "1234")</span><br /><span style="color: #000080; font-family: Courier;">c_redis.set("FOO", "1234", function(ok) print(ok) end)</span><br /><span style="color: #000080; font-family: Courier;">c_redis.get("FOO", function(reply_type, reply)</span><br /><span style="color: #000080; font-family: Courier;">&nbsp;&nbsp; &nbsp;assert("string" == type(reply))</span><br /><span style="color: #000080; font-family: Courier;">&nbsp;&nbsp; &nbsp;if 0 == reply_type or 1 == reply_type then</span><br /><span style="color: #000080; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;print("FOO="..reply)</span><br /><span style="color: #000080; font-family: Courier;">&nbsp;&nbsp; &nbsp;else</span><br /><span style="color: #000080; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;print("Error: "..reply)</span><br /><span style="color: #000080; font-family: Courier;">&nbsp;&nbsp; &nbsp;end</span><br /><span style="color: #000080; font-family: Courier;">end)</span></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214574.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2017-01-05 18:42 <a href="http://www.cppblog.com/jinq0123/archive/2017/01/05/214574.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hiredis的各种windows版本</title><link>http://www.cppblog.com/jinq0123/archive/2016/12/28/214562.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 28 Dec 2016 03:02:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2016/12/28/214562.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214562.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2016/12/28/214562.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214562.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214562.html</trackback:ping><description><![CDATA[<div>hiredis的各种windows版本<br /><br />(金庆的专栏 2016.12)<br /><br />hiredis 是内存数据库 redis 的客户端C库, 不支持Windows。<br /><br />hiredis的Windows移植版本有许多：<br /><br />desb42/hiredis<br />&nbsp;&nbsp; &nbsp;forked from redis/hiredis<br />&nbsp;&nbsp; &nbsp;hiredis 0.10.1<br />&nbsp;&nbsp; &nbsp;Star 3<br />&nbsp;&nbsp; &nbsp;<br />koenvandesande/hiredis<br />&nbsp;&nbsp; &nbsp;forked from redis/hiredis<br />&nbsp;&nbsp; &nbsp;hiredis 0.11.0<br />&nbsp;&nbsp; &nbsp;在日志中指出基于 desb42<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Windows compatability, partially based on desb42's patch, but with cleanup and additional fixes.<br />&nbsp;&nbsp; &nbsp;Star 8<br />&nbsp;&nbsp; &nbsp;<br />wasppdotorg/hiredis-for-windows<br />&nbsp;&nbsp; &nbsp;hiredis 0.13.3<br />&nbsp;&nbsp; &nbsp;README.md 头部指出基于 koenvandesande/hiredis<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;https://github.com/redis/hiredis (0.13.3)<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;https://github.com/koenvandesande/hiredis<br />&nbsp;&nbsp; &nbsp;Star 3<br />&nbsp;&nbsp; &nbsp;<br />lgsonic/hiredis-win <br />&nbsp;&nbsp; &nbsp;hiredis 0.10.1<br />&nbsp;&nbsp; &nbsp;Star 15<br /><br />texnician/hiredis-win32 <br />&nbsp;&nbsp; &nbsp;hiredis 0.10.1<br />&nbsp;&nbsp; &nbsp;Star 17<br />&nbsp;&nbsp; &nbsp;<br />Microsoft/hiredis <br />&nbsp;&nbsp; &nbsp;forked from redis/hiredis<br />&nbsp;&nbsp; &nbsp;hiredis 0.11.0<br />&nbsp;&nbsp; &nbsp;Star 11<br /><br />ayrb13/hiredis-win<br />&nbsp;&nbsp; &nbsp;hiredis 0.11.0<br />&nbsp;&nbsp; &nbsp;Star 1<br /><br />对于星星数都较少的情况，创建较早的 hiredis-win 和 hiredis-win32 星星数会占据优势，<br />但是星星意义不大。<br /><br />支持hiredis的版本是关键。<br />hiredis-for-windows 支持版本最新，并且渊源清楚，可以信赖。<br /><br />Microsoft/hiredis 顶着MS的牌子比较容易让人接受，因为是 forked from redis/hiredis，<br />所以升级 hiredis 只需处理下冲突就行了。<br />但是这个移植更改太大，使用了IOCP, 多了一个win32_interop, 不如其他移植简洁。<br />这应该是 MSOpenTech/redis 的子项目，见：<br />http://blog.sina.com.cn/s/blog_47379bd80102vbtb.html<br />Win32_Interop 重定义了一些Windows API以模拟Linux下的POSIX函数。<br />在项目中连接hiredis.lib和Win32_Interop.lib时，如果同时连接系统库文件，<br />则会出现一系列冲突。<br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214562.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2016-12-28 11:02 <a href="http://www.cppblog.com/jinq0123/archive/2016/12/28/214562.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>结构体初始化列表错误</title><link>http://www.cppblog.com/jinq0123/archive/2016/12/12/214479.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Mon, 12 Dec 2016 09:16:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2016/12/12/214479.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214479.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2016/12/12/214479.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214479.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214479.html</trackback:ping><description><![CDATA[<div>结构体初始化列表错误<br /><br />(金庆的专栏 2016.12)<br /><br /><span style="color: #800000; font-family: Courier;">struct A</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;int a = 0;</span><br /><span style="color: #800000; font-family: Courier;">};</span><br /><br /><span style="color: #800000; font-family: Courier;">int main()</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;A a{0};</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;return 0;</span><br /><span style="color: #800000; font-family: Courier;">}</span><br /><br />报以下错误：<br /><br />error C2440: &#8220;初始化&#8221;: 无法从&#8220;initializer list&#8221;转换为&#8220;A&#8221;<br />note: 无构造函数可以接受源类型，或构造函数重载决策不明确<br /><br />去除 A.a 的类内初始化就好了。<br /><br /><span style="color: #800000; font-family: Courier;">struct A</span><br /><span style="color: #800000; font-family: Courier;">{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;int a;</span><br /><span style="color: #800000; font-family: Courier;">};</span><br /><br />应该是添加类内初始化后，就不再有默认构造函数了。<br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214479.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2016-12-12 17:16 <a href="http://www.cppblog.com/jinq0123/archive/2016/12/12/214479.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++用LuaIntf调用Lua代码示例</title><link>http://www.cppblog.com/jinq0123/archive/2016/12/09/214475.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Fri, 09 Dec 2016 14:17:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2016/12/09/214475.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214475.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2016/12/09/214475.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214475.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214475.html</trackback:ping><description><![CDATA[<div><div id="article_content">         <div><h1>C++用LuaIntf调用Lua代码示例</h1>  <p>(金庆的专栏 2016.12)<br /></p><p><br style="color: #800000;" /></p><p><div><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp; void LuaTest::OnResponse(uint32_t uLuaRpcId,</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;const std::string&amp; sRespContent) const</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;using LuaIntf::LuaRef;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;LuaRef require(m_pLuaState, "require");</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;try {</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;LuaRef handler = require.call&lt;LuaRef&gt;("client_rpc_response_handler");</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;handler.dispatchStatic("handle", uLuaRpcId, sRespContent);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;catch (const LuaIntf::LuaException&amp; e) {</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;std::cerr &lt;&lt; "Failed to call lua client_rpc_response_handler.handle(), "</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;&lt; e.what() &lt;&lt; std::endl;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp; &nbsp;}</span></div><br /></p><p>这是测试客户端代码，可以写Lua代码测试服务器．  </p><p>Lua代码中发出一个Rpc请求时, 会在Lua中保存一个回调, 待收到应答时触发回调. 通过uLuaRpcId来索引该回调.</p>  <p>sRespContent 是收到的应答包, 将在lua中解包.</p>  <p>OnResponse() 就是调用了 Lua 代码:</p>  <pre><code><span style="color: #800000; font-family: Courier;">    require("client_rpc_response_handler").handle(uLuaRpcId, sRespContent) </span></code></pre></div>              </div>                                                                         </div><img src ="http://www.cppblog.com/jinq0123/aggbug/214475.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2016-12-09 22:17 <a href="http://www.cppblog.com/jinq0123/archive/2016/12/09/214475.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>log4cxx用环境变量设置输出文件名</title><link>http://www.cppblog.com/jinq0123/archive/2016/12/05/214461.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Mon, 05 Dec 2016 07:31:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2016/12/05/214461.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214461.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2016/12/05/214461.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214461.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214461.html</trackback:ping><description><![CDATA[<div>log4cxx用环境变量设置输出文件名<br /><br />(金庆的专栏 2016.12)<br /><br />利用环境变量，可以用同一个log4j.xml来配置多个相似进程，输出日志到不同文件。<br /><br />例如多个BaseApp进程使用同一个BaseApp.xml配置, SERVER_ID为环境变量：<br /><br /><span style="color: #800000;">&nbsp; &lt;appender name="ROLLING" class="org.apache.log4j.RollingFileAppender"&gt; &nbsp;</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param name="File" value="log/BaseApp_${SERVER_ID}.log" /&gt;</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... &nbsp;</span><br /><span style="color: #800000;">&nbsp; &lt;/appender&gt;</span><br /><br />代码启动时先读取server_id参数，然后设置 SERVER_ID 环境变量，然后再配置log4cxx.<br /><br /><span style="color: #800000;">int main(int argc, char* argv[])</span><br /><span style="color: #800000;">{</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;log4cxx::NDC ndcMain("");</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;if (argc &lt; 3)</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;LOG_ERROR(Fmt("Usage: %s cfg_file server_id") % argv[0]);</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return -1;</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;}</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;uint16_t uServerId = (uint16_t)atoi(argv[2]);</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;if (!Util::SetServerIdEnv(uServerId))&nbsp; // for log4cxx</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return -1;</span><br /><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;// Must after SetServerIdEnv().</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;log4cxx::xml::DOMConfigurator::configureAndWatch("log4j/BaseApp.xml", 5000);</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;LOG_INFO("--------------------------- ");</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;LOG_INFO(Fmt("Start base app (ID=%1%).") % uServerId);</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;LOG_INFO("--------------------------- ");</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;...</span><br /><span style="color: #800000;">} &nbsp;</span><br /><br />SetServerIdEnv() 如下：<br /><br /><span style="color: #800000;">bool SetServerIdEnv(uint16_t uServerId)</span><br /><span style="color: #800000;">{</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;const char LOG_NAME[] = "SetServerIdEnv";</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;static char buf[128] = {0};&nbsp; // putenv need a buffer</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;int nLen = snprintf(buf, sizeof(buf), "SERVER_ID=%u", uServerId);</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;if (nLen &lt; 0)</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;LOG_ERROR(Fmt("snprintf() failed. (%1%)%2%") % errno % strerror(errno));</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return false;</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;}</span><br /><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;int nErr = putenv(buf);</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;if (0 == nErr) return true;</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;LOG_ERROR(Fmt("putenv() failed. (%1%)%2%") % errno % strerror(errno));</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;return false;</span><br /><span style="color: #800000;">}</span><br /><br />运行目录下有个log4cxx缺省配置 log4j.xml, 会自动加载，<br />所以在 log4cxx 显式配置之前也可以调用日志输出。<br /><br />运行多个BaseApp.exe:<br /><br /><span style="color: #000080;">start&nbsp; Debug\Giant_BaseApp.exe&nbsp; cfg.ini 4</span><br /><span style="color: #000080;">start&nbsp; Debug\Giant_BaseApp.exe&nbsp; cfg.ini 3</span><br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214461.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2016-12-05 15:31 <a href="http://www.cppblog.com/jinq0123/archive/2016/12/05/214461.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>gdb不知为何显示2次析构</title><link>http://www.cppblog.com/jinq0123/archive/2016/11/18/214421.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Fri, 18 Nov 2016 08:19:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2016/11/18/214421.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214421.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2016/11/18/214421.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214421.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214421.html</trackback:ping><description><![CDATA[<div>gdb不知为何显示2次析构<br /><br />(金庆的专栏 2016.11)<br /><br />gdb 显示2次 A::~A():<br /><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; (gdb) bt</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; #0&nbsp; A::~A (this=0x602010, __in_chrg=&lt;optimized out&gt;) at main.cpp:10</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; #1&nbsp; 0x0000000000400a96 in A::~A (this=0x602010, __in_chrg=&lt;optimized out&gt;)</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at main.cpp:12</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; #2&nbsp; 0x00000000004009c0 in main () at main.cpp:18</span><br /><br />代码如下：<br /><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp; class A</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp; {</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp; public:</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A() {}</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual ~A() </span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; "~A()" &lt;&lt; endl;</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp; };</span><br />&nbsp;&nbsp; &nbsp;<br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp; int main()</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp; {</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A* p = new A;</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete p;</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp; }</span><br />&nbsp;&nbsp; &nbsp;<br />打断点显示：2 locations:<br /><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; (gdb) b A::~A</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; Breakpoint 1 at 0x400a40: A::~A. (2 locations)</span><br /><br />完整的 gdb 输出:<br /><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; g++ -g main.cpp</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; [jinq@localhost test]$ gdb a.out</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; Copyright (C) 2013 Free Software Foundation, Inc.</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; License GPLv3+: GNU GPL version 3 or later &lt;http://gnu.org/licenses/gpl.html&gt;</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; This is free software: you are free to change and redistribute it.</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; There is NO WARRANTY, to the extent permitted by law.&nbsp; Type "show copying"</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; and "show warranty" for details.</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; This GDB was configured as "x86_64-redhat-linux-gnu".</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; For bug reporting instructions, please see:</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; &lt;http://www.gnu.org/software/gdb/bugs/&gt;...</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; Reading symbols from /home/jinq/test/a.out...done.</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; (gdb) b A::~A</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; Breakpoint 1 at 0x400a40: A::~A. (2 locations)</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; (gdb) run</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; Starting program: /home/jinq/test/a.out</span><br />&nbsp;&nbsp; &nbsp;<br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; Breakpoint 1, A::~A (this=0x602010, __in_chrg=&lt;optimized out&gt;) at main.cpp:12</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; 12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; Missing separate debuginfos, use: debuginfo-install glibc-2.17-106.el7_2.8.x86_64 libgcc-4.8.5-4.el7.x86_64 libstdc++-4.8.5-4.el7.x86_64</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; (gdb) bt</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; #0&nbsp; A::~A (this=0x602010, __in_chrg=&lt;optimized out&gt;) at main.cpp:12</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; #1&nbsp; 0x00000000004009c0 in main () at main.cpp:18</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; (gdb) s</span><br />&nbsp;&nbsp; &nbsp;<br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; Breakpoint 1, A::~A (this=0x602010, __in_chrg=&lt;optimized out&gt;) at main.cpp:10</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; (gdb) bt</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; #0&nbsp; A::~A (this=0x602010, __in_chrg=&lt;optimized out&gt;) at main.cpp:10</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; #1&nbsp; 0x0000000000400a96 in A::~A (this=0x602010, __in_chrg=&lt;optimized out&gt;)</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; at main.cpp:12</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; #2&nbsp; 0x00000000004009c0 in main () at main.cpp:18</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; (gdb) ^CQuit</span><br /><span style="color: #000080;">&nbsp;&nbsp;&nbsp; (gdb)</span><br /><br />虚析构函数并且是delete才这样。<br /><br />Also see: http://lists.qt-project.org/pipermail/interest/2015-November/019691.html<br /><br />已提交Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=20837<br /><br /><br />&nbsp;&nbsp;&nbsp;</div><img src ="http://www.cppblog.com/jinq0123/aggbug/214421.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2016-11-18 16:19 <a href="http://www.cppblog.com/jinq0123/archive/2016/11/18/214421.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>gloox配置聊天室</title><link>http://www.cppblog.com/jinq0123/archive/2016/09/28/214309.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 28 Sep 2016 09:44:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2016/09/28/214309.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214309.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2016/09/28/214309.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214309.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214309.html</trackback:ping><description><![CDATA[<div>gloox配置聊天室<br /><br />(金庆的专栏)<br /><br />gloox是XMPP协议的C++客户端库。<br />以下代码测试创建多人聊天室(MUC), 并进行配置。<br />参照gloox中的muc示例代码。<br />gloox代码示例中没有聊天室的配置。<br />配置聊天室需要获取配置表单(DataForm), 填好表单然后调用 setRoomConfig().<br />配置表单读取服务器发来的默认配置，仅更改了其中一项。<br />测试服务器使用了ejabberd.<br /><br /><span style="font-family: Courier; color: #800000;">const char SERVER[] = "xmpp.jinqing.net";</span><br /><span style="font-family: Courier; color: #800000;">const char TESTER[] = "tester";</span><br /><span style="font-family: Courier; color: #800000;">const char PASSWORD[] = "password";</span><br /><br /><span style="font-family: Courier; color: #800000;">using namespace gloox;</span><br /><br /><span style="font-family: Courier; color: #800000;">static std::string GetTesterJid()</span><br /><span style="font-family: Courier; color: #800000;">{</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;return std::string(TESTER) + "@" + SERVER;</span><br /><span style="font-family: Courier; color: #800000;">}</span><br /><br /><span style="font-family: Courier; color: #800000;">static DataForm* CreateMUCConfigForm(const DataForm&amp; form)</span><br /><span style="font-family: Courier; color: #800000;">{</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;DataForm* pNewFm = new DataForm(TypeSubmit);</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;const DataForm::FieldList&amp; fl = form.fields();</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;for (const DataFormField* pFld : fl)</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;DataFormField* pNewFld = pNewFm-&gt;addField(</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;pFld-&gt;type(), pFld-&gt;name(), pFld-&gt;value());</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (pFld-&gt;name() == "muc#roomconfig_roomdesc")</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;pNewFld-&gt;setValue("RoomDesc_JinqTest");</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;}</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;return pNewFm;</span><br /><span style="font-family: Courier; color: #800000;">}</span><br /><br /><span style="font-family: Courier; color: #800000;">class MUCRoomConfigHandlerTest : public MUCRoomConfigHandler</span><br /><span style="font-family: Courier; color: #800000;">{</span><br /><span style="font-family: Courier; color: #800000;">public:</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;void handleMUCConfigList(MUCRoom* room, const MUCListItemList&amp; items,</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;MUCOperation operation) override {}</span><br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;void handleMUCConfigForm(MUCRoom* room, const DataForm&amp; form) override</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;DataForm* pNewForm = CreateMUCConfigForm(form);&nbsp; // deleted in setRoomConfig()</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;room-&gt;setRoomConfig(pNewForm);</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;}</span><br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;void handleMUCConfigResult(MUCRoom* room, bool success,</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;MUCOperation operation) override {}</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;void handleMUCRequest(MUCRoom* room, const DataForm&amp; form) override {}</span><br /><span style="font-family: Courier; color: #800000;">};&nbsp; // class MUCRoomConfigHandlerTest</span><br /><br /><span style="font-family: Courier; color: #800000;">class CreateRoomTest : public ConnectionListener, MUCRoomHandler</span><br /><span style="font-family: Courier; color: #800000;">{</span><br /><span style="font-family: Courier; color: #800000;">public:</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;CreateRoomTest() : m_client(JID(GetTesterJid()), PASSWORD)</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;m_client.registerConnectionListener(this);</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;}</span><br /><br /><span style="font-family: Courier; color: #800000;">public:</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;void TestCreate()</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;m_client.setPresence(Presence::Available, -1);</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;JID nick(std::string("gloox@conference.") + SERVER + "/gloox");</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;m_pRoom.reset(new MUCRoom(&amp;m_client, nick, this, &amp;m_cfgHdlr));</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;m_client.connect();</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;}</span><br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;void onConnect() override</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;m_pRoom-&gt;join();</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;m_pRoom-&gt;requestRoomConfig();</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;}</span><br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;void onDisconnect(ConnectionError /*e*/) override {}</span><br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;bool onTLSConnect(const CertInfo&amp; info) override</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return true;</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;}</span><br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;void handleMUCParticipantPresence(MUCRoom * /*room*/,</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;const MUCRoomParticipant participant,</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;const Presence&amp; presence) override {}</span><br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;void handleMUCMessage(MUCRoom* /*room*/,</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;const Message&amp; msg, bool priv) override {}</span><br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;void handleMUCSubject(MUCRoom * /*room*/, const std::string&amp; nick,</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;const std::string&amp; subject) override {}</span><br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;void handleMUCError(MUCRoom * /*room*/, StanzaError error) override {}</span><br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;void handleMUCInfo(MUCRoom * /*room*/, int features,</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;const std::string&amp; name, const DataForm* infoForm) override {}</span><br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;void handleMUCItems(MUCRoom * /*room*/,</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;const Disco::ItemList&amp; items) override {}</span><br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;void handleMUCInviteDecline(MUCRoom * /*room*/, const JID&amp; invitee,</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;const std::string&amp; reason) override {}</span><br /><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;bool handleMUCRoomCreation(MUCRoom *room) override</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;{</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return true;</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;}</span><br /><br /><span style="font-family: Courier; color: #800000;">private:</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;gloox::Client m_client;</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;MUCRoomConfigHandlerTest m_cfgHdlr;</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;std::unique_ptr&lt;MUCRoom&gt; m_pRoom;</span><br /><span style="font-family: Courier; color: #800000;">};&nbsp; // class CreateRoomTest</span><br /><br /><span style="font-family: Courier; color: #800000;">int main()</span><br /><span style="font-family: Courier; color: #800000;">{</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;CreateRoomTest().TestCreate();</span><br /><span style="font-family: Courier; color: #800000;">&nbsp;&nbsp; &nbsp;return 0;</span><br /><span style="font-family: Courier; color: #800000;">}</span><br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214309.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2016-09-28 17:44 <a href="http://www.cppblog.com/jinq0123/archive/2016/09/28/214309.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>