??xml version="1.0" encoding="utf-8" standalone="yes"?>麻豆精品久久精品色综合,久久亚洲高清观看,四虎国产精品免费久久5151http://www.shnenglu.com/mymsdn/category/7975.htmlMyMSDN记录开发新知道zh-cnSun, 20 Mar 2011 12:47:46 GMTSun, 20 Mar 2011 12:47:46 GMT60关于protobuf中的field_number范围的解?/title><link>http://www.shnenglu.com/mymsdn/archive/2011/03/19/142184.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Fri, 18 Mar 2011 18:01:00 GMT</pubDate><guid>http://www.shnenglu.com/mymsdn/archive/2011/03/19/142184.html</guid><wfw:comment>http://www.shnenglu.com/mymsdn/comments/142184.html</wfw:comment><comments>http://www.shnenglu.com/mymsdn/archive/2011/03/19/142184.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/mymsdn/comments/commentRss/142184.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/mymsdn/services/trackbacks/142184.html</trackback:ping><description><![CDATA[<!--MyMSDN style!--><link rel="stylesheet" type="text/css" > <style type="text/css"> body{background-color:#eeeeee;} </style> <div>以下是来自Google Protobuf Documents里的一句话Q?</div> <div id="846we8k" class="quote">As you can see, each field in the message definition has a unique numbered tag. These tags are used to identify your fields in the <a >message binary format</a>, and should not be changed once your message type is in use. Note that tags with values in the range 1 through 15 take one byte to encode. Tags in the range 16 through 2047 take two bytes. So you should reserve the tags 1 through 15 for very frequently occurring message elements. Remember to leave some room for frequently occurring elements that might be added in the future. </div> <div>q里要做一个解释,是Z么是1?5Q以?6?047呢?</div> <div> <ol> <li>1?5Q仅使用1bytes。每个byte包含两个部分Q一个是field_number一个是tagQ其中field-number是protobuf中每个值后{号后的数字Q在C++和Java中,如果不设|这个|则它是随机的Q如果在Python中,不设|,它则不被处理Q这个在<a >message binary format</a>中的Field Order一节中有提刎ͼ。那么我们可以认个field_number是必ȝ。那么一个byte用来表达q个值就?span style="color: red">0</span><span style="color: blue">00000</span><span style="color: green">000</span>Q其中红色表C是否有后箋字节Q如果ؓ0表示没有也就是这是一个字节,蓝色部分表示field-numberQ绿色部分则是wire_type部分Q表C数据类型。也是(field_number << 3) | wire_type。其中wire_type只有3位,表示数据cd。那么能够表Cfield_number的就?位蓝色的数字Q?位数字能够表辄最大范围就?-15Q其?是无效的Q? <li>16?047Q与上面的规则其实类|下面?bytesZ子,那么有<span style="color: red">1</span><span style="color: blue">0000000 <span style="color: red">0</span>0000</span><span style="color: green">000</span>Q其中红色部分依然是W号位,因ؓ每个byte的第一位都用来表示下一byte是否和自己有养I那么对于>1byte的数据,W一位一定是1Q因里假设是2byteQ那么第二个byte的第一位也是红Ԍ刨除q两位,再扣?个wire_type位,剩下11位(2*8-2-3Q,能够表达的数字范围就?047Q?<sup>11</sup>Q?/li></ol></div> <div> 参考资料:<br /> <ol><li>http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/proto.html</li> <li>http://code.google.com/apis/protocolbuffers/docs/encoding.html</li></ol> </div><img src ="http://www.shnenglu.com/mymsdn/aggbug/142184.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/mymsdn/" target="_blank">volnet</a> 2011-03-19 02:01 <a href="http://www.shnenglu.com/mymsdn/archive/2011/03/19/142184.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>zig-zag~码方式http://www.shnenglu.com/mymsdn/archive/2011/03/19/zig-zag-encoding.htmlvolnetvolnetFri, 18 Mar 2011 16:36:00 GMThttp://www.shnenglu.com/mymsdn/archive/2011/03/19/zig-zag-encoding.htmlhttp://www.shnenglu.com/mymsdn/comments/142182.htmlhttp://www.shnenglu.com/mymsdn/archive/2011/03/19/zig-zag-encoding.html#Feedback0http://www.shnenglu.com/mymsdn/comments/commentRss/142182.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/142182.htmlhttp://goo.gl/2wRKb
用位q算来表C把一个负数{换成zig-zag~码Q就?span class="pun">

int32是:(n << 1) ^ (n >> 31)
int64是:(n << 1) ^ (n >> 63)
也就是说Q如果是负数Q对?2位最多能省去30|其中1格是W号位,另一个代表最?Q此处假?#8220;正负0”不合法)。同理,64位最多能省去62位。当然比较极端的是所有的位数都被用上了?br>



volnet 2011-03-19 00:36 发表评论
]]>
IsWow64q不能用来检是否是Windows 32bitpȝq是64bitpȝhttp://www.shnenglu.com/mymsdn/archive/2010/09/06/125966.htmlvolnetvolnetSun, 05 Sep 2010 18:06:00 GMThttp://www.shnenglu.com/mymsdn/archive/2010/09/06/125966.htmlhttp://www.shnenglu.com/mymsdn/comments/125966.htmlhttp://www.shnenglu.com/mymsdn/archive/2010/09/06/125966.html#Feedback10http://www.shnenglu.com/mymsdn/comments/commentRss/125966.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/125966.html如何当前操作pȝ是不?4位?如何判断当前应用E序是否在Wow64下运行?

首先什么是Wow64Q很多朋友一看到64p个方法是判断当前pȝ是否?4bit的,其实不然。Wow64是Windows-On-Windows64的意思,它是指在64位的操作pȝ上(不是?4位的CPUQ运?2位应用程序的兼容q_?/p>

下面是MSDN中一DIsWow64的应用程序:

BOOL IsWow64() 
{ 
    typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); 
    LPFN_ISWOW64PROCESS fnIsWow64Process; 
    BOOL bIsWow64 = FALSE; 
    fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress( GetModuleHandle(_T("kernel32")), "IsWow64Process"); 
    if (NULL != fnIsWow64Process) 
    {
        fnIsWow64Process(GetCurrentProcess(),&bIsWow64); 
    } 
    return bIsWow64; 
}

下面的代码用来检这个程序的l果Q?/p>

if( IsWow64() == TRUE )
{
    _tprintf(_T("IsWow64() == TRUE\n"));
}
else
{
    _tprintf(_T("IsWow64() == FALSE\n"));
}

让我们编译一下这个程序?/p>

我们需要的?4位的操作pȝQ比如XP64bitQWindows 2008 R2{都?4bit操作pȝ?/p>

?4位的操作pȝ上运行的kernel32.dll中,会实现IsWow64ProcessҎQ而在32位系l中提供的kernel32.dll中则没有提供相关函数的实现?/p>

比较qh人的则是bIsWow64Q其实仔l看MSDN中的RemarkQ会发现Q?/p>

If the application is a 64-bit application running under 64-bit Windows, the Wow64Process parameter is set to FALSE.也就是说64位应用程序跑?4位的操作pȝ上,bIsWow64的值将是FALSE而不是TRUE?

因此我们需要分别将我们的程序编译成Win32q_和x64q_的,如果你用Visual Studioq行~译Q默认安装则只包?2位的~译?链接器,即便你是?4位操作系l上安装Q也是一L。你需要在VC++节点下勾选x64选项才可以,Itanium则需要在Serverq_下安装才可勾选。然后在~译的时候,分别选择Win32和x64q行~译?

image

~译后,q行Q结果如我们分析的一P

?4位系l上q行Win32~译配置的结果是IsWow64() == TRUEQ而x64~译配置的结果是IsWow64() == FALSE?

如果惌知道当前pȝ是否?4位的Q则可以通过下面的方法:

BOOL Is64bitSystem()
{
    SYSTEM_INFO si;
    GetNativeSystemInfo(&si);

    if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||    
        si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 )
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    } 
}

注意Q需要注意是GetNativeSystemInfo  函数从Windows XP 开始才有, ?IsWow64Process  函数?Windows XP with SP2 以及 Windows Server 2003 with SP1 开始才有?



volnet 2010-09-06 02:06 发表评论
]]>
q?amp;reg; 多线E应用开发指?/title><link>http://www.shnenglu.com/mymsdn/archive/2010/09/05/125912.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Sat, 04 Sep 2010 18:20:00 GMT</pubDate><guid>http://www.shnenglu.com/mymsdn/archive/2010/09/05/125912.html</guid><wfw:comment>http://www.shnenglu.com/mymsdn/comments/125912.html</wfw:comment><comments>http://www.shnenglu.com/mymsdn/archive/2010/09/05/125912.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/mymsdn/comments/commentRss/125912.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/mymsdn/services/trackbacks/125912.html</trackback:ping><description><![CDATA[     摘要: http://software.intel.com/zh-cn/articles/intel-guide-for-developing-multithreaded-applications/ q?多线E应用开发指?提交新文? Published On :  2010q?2?5?20:00 评 L录后评Q当前分敎ͼ 0 ?0 用户 L录后评Q当前分敎ͼ 0 ...  <a href='http://www.shnenglu.com/mymsdn/archive/2010/09/05/125912.html'>阅读全文</a><img src ="http://www.shnenglu.com/mymsdn/aggbug/125912.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/mymsdn/" target="_blank">volnet</a> 2010-09-05 02:20 <a href="http://www.shnenglu.com/mymsdn/archive/2010/09/05/125912.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]C/C++中动态链接库的创建和调用http://www.shnenglu.com/mymsdn/archive/2010/08/28/124983.htmlvolnetvolnetFri, 27 Aug 2010 16:30:00 GMThttp://www.shnenglu.com/mymsdn/archive/2010/08/28/124983.htmlhttp://www.shnenglu.com/mymsdn/comments/124983.htmlhttp://www.shnenglu.com/mymsdn/archive/2010/08/28/124983.html#Feedback1http://www.shnenglu.com/mymsdn/comments/commentRss/124983.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/124983.html转蝲自:http://developer.51cto.com/art/200702/39608.htm

动态连接库的创建步骤:

一、创建Non-MFC DLL动态链接库

1、打开File ?gt; New ?gt; Project选项Q选择Win32 Dynamic-Link Library ?gt;sample project ?gt;工程名:DllDemo

2、新Z?h文gDllDemo.h

#ifdef DllDemo_EXPORTS
#define DllAPI __declspec(dllexport)
#else
#define DllAPI __declspec(dllimport)
extern "C" //原样~译
{
DllAPI int __stdcall Max(int a,int b); //__stdcall佉KC/C++语言内能够调用API
}
#endif

3、在DllDemo.cpp文g中导入DllDemo.h文gQƈ实现Max(int,int)函数

#include "DllDemo.h"
DllAPI int __stdcall Max(int a,int b)
{
if(a==b)
return NULL;
else if(a>b)
return a;
else
return b;
}

4、编译程序生成动态连接库

二、用.def文g创徏动态连接库DllDemo.dll

1、删除DllDemo工程中的DllDemo.h文g?

2、在DllDemo.cpp文g_删除 #include DllDemo.h语句?

3、向该工E中加入一个文本文Ӟ命名为DllDemo.defq写入如下语句:

LIBRARY MyDll

EXPORTS

Max@1

4、编译程序生成动态连接库?

动态链接的调用步骤Q?/strong>

一、隐式调?/strong>

1、徏立DllCnslTest工程

2、将文gDllDemo.dll、DllDemo.lib拯到DllCnslTest工程所在的目录

3、在DllCnslTest.h中添加如下语句:

#define DllAPI __declspec(dllimport)
#pragma comment(libQ?DllDemo.lib") //在编辑器linkӞ链接到DllDemo.lib文g
extern "C"
{
DllAPI int __stdcall Max(int a,int b);
}

4、在DllCnslTest.cpp文g中添加如下语句:

#include "DllCnslTest.h"http://或?#include "DllDemo.h"
void main()
{
int value;
value = Max(2,9);
printf("The Max value is %d\n",value);
}

5、编译ƈ生成应用E序DllCnslTest.exe

二、显式调?/strong>

1、徏立DllWinTest工程?

2、将文gDllDemo.dll拯到DllWinTest工程所在的目录或Windowspȝ目录下?

3、用vc/bin下的Dumpbin.exe的小E序Q查看DLL文g(DllDemo.dll)中的函数l构?

4、用类型定义关键字typedefQ定义指向和DLL中相同的函数原型指针?

例:

typedef int(*lpMax)(int a,int b); //此语句可以放?h文g?/p>

5、通过LoadLibray()DLL加蝲到当前的应用E序中ƈq回当前DLL文g的句柄?

例:

HINSTANCE hDll; //声明一个Dll实例文g句柄
hDll = LoadLibrary("DllDemo.dll");//导入DllDemo.dll动态连接库

6、通过GetProcAddress()函数获取导入到应用程序中的函数指针?

例:

lpMax Max;
Max = (lpMax)GetProcAddress(hDLL,"Max");
int value;
value = Max(2,9);
printf("The Max value is %d",value);

7、函数调用完毕后Q用FreeLibrary()卸蝲DLL文g?pre>

FreeLibrary(hDll);

8、编译ƈ生成应用E序DllWinTest.exe

注:昑ּ链接应用E序~译时不需要用相应的Lib文g?/p>

下蝲Q?font style="background-color: #cccccc">Visual Studio 2008验证通过Q:http://www.shnenglu.com/Files/mymsdn/DllCnsTest.7z



volnet 2010-08-28 00:30 发表评论
]]>
两个有用的宏Q?amp;ldquo;止cL员复?amp;rdquo;以及&ldquo;止隐式构?amp;rdquo;http://www.shnenglu.com/mymsdn/archive/2010/08/11/123003.htmlvolnetvolnetTue, 10 Aug 2010 16:34:00 GMThttp://www.shnenglu.com/mymsdn/archive/2010/08/11/123003.htmlhttp://www.shnenglu.com/mymsdn/comments/123003.htmlhttp://www.shnenglu.com/mymsdn/archive/2010/08/11/123003.html#Feedback1http://www.shnenglu.com/mymsdn/comments/commentRss/123003.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/123003.html止cL员复Ӟ其核心就在于不允许类外部看见复制函数Q包?#8220;拯构造函?#8221;?#8220;operator =重蝲”?/p>
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
private:                     \
TypeName(const TypeName&);               \
TypeName& operator=(const TypeName&)
止隐式构造,则可以将默认构造函数隐藏v来,在大多数~译器中也可以对构造函数增加explicit关键字来避免隐式构造?
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
private:                     \
TypeName();                                    \
DISALLOW_COPY_AND_ASSIGN(TypeName)
更多解释详见《More Effective C++?

volnet 2010-08-11 00:34 发表评论
]]>
[C++]__declspec关键?/title><link>http://www.shnenglu.com/mymsdn/archive/2010/07/22/121059.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Thu, 22 Jul 2010 12:46:00 GMT</pubDate><guid>http://www.shnenglu.com/mymsdn/archive/2010/07/22/121059.html</guid><wfw:comment>http://www.shnenglu.com/mymsdn/comments/121059.html</wfw:comment><comments>http://www.shnenglu.com/mymsdn/archive/2010/07/22/121059.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/mymsdn/comments/commentRss/121059.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/mymsdn/services/trackbacks/121059.html</trackback:ping><description><![CDATA[<p><span style="color: blue">__declspec</span>关键?/p><pre class="gc-code"><span style="color: green">// keyword__declspec.cpp : 定义控制台应用程序的入口炏V? // // ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/kernel_d/hh/Kernel_d/64bitAMD_6db3322a-fe6d-4287-9eda-a9c1378e715d.xml.htm // The sizeof value for any structure is the offset of the final member, // plus that member's size, rounded up to the nearest multiple of the largest // member alignment value or the whole structure alignment value, // whichever is greater. </span><span style="color: blue">#include </span><span style="color: #a31515">"stdafx.h" </span><span style="color: blue">__declspec</span>( <span style="color: blue">align</span>( 32) ) <span style="color: blue">struct </span><span style="color: #010001">Struct__declspec_1 </span>{ <span style="color: blue">int </span><span style="color: #010001">a</span>; <span style="color: blue">int </span><span style="color: #010001">b</span>; }; <span style="color: blue">__declspec</span>( <span style="color: blue">align</span>( 32) ) <span style="color: blue">struct </span><span style="color: #010001">Struct__declspec_2 </span>{ <span style="color: blue">__declspec</span>( <span style="color: blue">align</span>( 64) ) <span style="color: blue">int </span><span style="color: #010001">a</span>; <span style="color: blue">int </span><span style="color: #010001">b</span>; }; <span style="color: blue">__declspec</span>( <span style="color: blue">align</span>( 8 ) ) <span style="color: blue">struct </span><span style="color: #010001">Struct__declspec_3 </span>{ <span style="color: blue">int </span><span style="color: #010001">a</span>; <span style="color: green">//4 bytes </span><span style="color: blue">int </span><span style="color: #010001">b</span>; <span style="color: green">//4 bytes </span><span style="color: blue">int </span><span style="color: #010001">c</span>; <span style="color: green">//4 bytes </span>}; <span style="color: blue">__declspec</span>( <span style="color: blue">align</span>( 8 ) ) <span style="color: blue">struct </span><span style="color: #010001">Struct__declspec_4 </span>{ <span style="color: blue">int </span><span style="color: #010001">a</span>; <span style="color: green">//4 bytes </span><span style="color: blue">int </span><span style="color: #010001">b</span>; <span style="color: green">//4 bytes </span>}; <span style="color: blue">struct </span><span style="color: #010001">StructNormal </span>{ <span style="color: blue">int </span><span style="color: #010001">a</span>; <span style="color: green">//4 bytes </span><span style="color: blue">int </span><span style="color: #010001">b</span>; <span style="color: green">//4 bytes </span><span style="color: blue">int </span><span style="color: #010001">c</span>; <span style="color: green">//4 bytes </span>}; <span style="color: blue">int </span><span style="color: #010001">_tmain</span>(<span style="color: blue">int </span><span style="color: #010001">argc</span>, <span style="color: #010001">_TCHAR</span>* <span style="color: #010001">argv</span>[]) { <span style="color: #010001">printf</span>( <span style="color: #a31515">"sizeof Struct__declspec_1 is %d.\n"</span>, <span style="color: blue">sizeof</span>( <span style="color: #010001">Struct__declspec_1 </span>)); <span style="color: green">//32 </span><span style="color: #010001">printf</span>( <span style="color: #a31515">"sizeof Struct__declspec_2 is %d.\n"</span>, <span style="color: blue">sizeof</span>( <span style="color: #010001">Struct__declspec_2 </span>)); <span style="color: green">//64 </span><span style="color: #010001">printf</span>( <span style="color: #a31515">"sizeof Struct__declspec_3 is %d.\n"</span>, <span style="color: blue">sizeof</span>( <span style="color: #010001">Struct__declspec_3 </span>)); <span style="color: green">//16 </span><span style="color: #010001">printf</span>( <span style="color: #a31515">"sizeof Struct__declspec_4 is %d.\n"</span>, <span style="color: blue">sizeof</span>( <span style="color: #010001">Struct__declspec_4 </span>)); <span style="color: green">//8 </span><span style="color: #010001">printf</span>( <span style="color: #a31515">"sizeof StructNormal is %d.\n"</span>, <span style="color: blue">sizeof</span>( <span style="color: #010001">StructNormal </span>)); <span style="color: green">//12 </span><span style="color: blue">return </span>0; } </pre><img src ="http://www.shnenglu.com/mymsdn/aggbug/121059.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/mymsdn/" target="_blank">volnet</a> 2010-07-22 20:46 <a href="http://www.shnenglu.com/mymsdn/archive/2010/07/22/121059.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[C++]内存理Q?Q?/title><link>http://www.shnenglu.com/mymsdn/archive/2010/07/06/memory_manager-1.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Tue, 06 Jul 2010 14:45:00 GMT</pubDate><guid>http://www.shnenglu.com/mymsdn/archive/2010/07/06/memory_manager-1.html</guid><wfw:comment>http://www.shnenglu.com/mymsdn/comments/119492.html</wfw:comment><comments>http://www.shnenglu.com/mymsdn/archive/2010/07/06/memory_manager-1.html#Feedback</comments><slash:comments>17</slash:comments><wfw:commentRss>http://www.shnenglu.com/mymsdn/comments/commentRss/119492.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/mymsdn/services/trackbacks/119492.html</trackback:ping><description><![CDATA[     摘要: 和大多数内存理的初衷一_希望能够控制内存分配和回Ӟ减少内存片Q且通常q样的内存都会预开一D连l内存空_然后我们自己来管理这D内存。当焉常q样的需求都很合理,但是实现h则通常不能完美Q比如:效率、算法的选择、如何减内存碎片、跟t管理内存分配、性能、对pȝ内存使用的统计、垃圑֛收等。下面是我近期实现的一个非常简陋的E序Q甚臛_能连基本的要求都无法辑ֈQ大家帮忙看看,它究竟有多少~点...  <a href='http://www.shnenglu.com/mymsdn/archive/2010/07/06/memory_manager-1.html'>阅读全文</a><img src ="http://www.shnenglu.com/mymsdn/aggbug/119492.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/mymsdn/" target="_blank">volnet</a> 2010-07-06 22:45 <a href="http://www.shnenglu.com/mymsdn/archive/2010/07/06/memory_manager-1.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>~译旧程序的时候,可能需要手动关闭UAC选项Q否则可能程序无法运?/title><link>http://www.shnenglu.com/mymsdn/archive/2010/07/02/119127.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Thu, 01 Jul 2010 17:14:00 GMT</pubDate><guid>http://www.shnenglu.com/mymsdn/archive/2010/07/02/119127.html</guid><wfw:comment>http://www.shnenglu.com/mymsdn/comments/119127.html</wfw:comment><comments>http://www.shnenglu.com/mymsdn/archive/2010/07/02/119127.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/mymsdn/comments/commentRss/119127.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/mymsdn/services/trackbacks/119127.html</trackback:ping><description><![CDATA[<p>今天在VS2008下编译VS自带Sample中的一个例子,TstConQ因Z前的机器装的是XPpȝQ该E序曾成功编译过Q不q今天在Windows Server 2008 R2下打开p|Q在朋友的Windows 7 Ultimate下打开也失败,试用以管理员w䆾q行Q失败,试用修改兼容性选项为Windows XP SP3/SP2方式Q均p|?/p> <p>其实q个时候可能是一些Vista以上版本的OS所提供的新功能引v的限制。就当前的这个例子而言Q是因ؓ~译的时候,启用用户帐户控制(UAC)默认为“是”所_解x案内所有工E选中Q右键属性,修改“配|属性?>“链接器?>“清单文件?>“启用用户帐h?UAC)”ؓ“否”,重新生成解决ҎQ即可?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/mymsdn/WindowsLiveWriter/f6ec3fce6e75_FC5/image_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" class="wlDisabledImage" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/mymsdn/WindowsLiveWriter/f6ec3fce6e75_FC5/image_thumb.png" width="770" height="564"></a></p><img src ="http://www.shnenglu.com/mymsdn/aggbug/119127.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/mymsdn/" target="_blank">volnet</a> 2010-07-02 01:14 <a href="http://www.shnenglu.com/mymsdn/archive/2010/07/02/119127.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>size_t的倒序遍历问题http://www.shnenglu.com/mymsdn/archive/2010/06/30/119021.htmlvolnetvolnetWed, 30 Jun 2010 15:51:00 GMThttp://www.shnenglu.com/mymsdn/archive/2010/06/30/119021.htmlhttp://www.shnenglu.com/mymsdn/comments/119021.htmlhttp://www.shnenglu.com/mymsdn/archive/2010/06/30/119021.html#Feedback11http://www.shnenglu.com/mymsdn/comments/commentRss/119021.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/119021.html准确地说q是l验不Q这么简单的事居然想了好几分钟,当然也要怪VS在没有重新生成前的诡异现象?/p>

今晚在类中加入两个数l用来做计数Q因Z前代码有所改动QVS~译Q增量)的结果居然出C无数ơ的E序崩溃Q害我一度怀疑是不是我的数组写的有问题。囧。最后无奈之下,点了重新生成Q居焉利通过了,很生气,愤怒中?/p>

但是另外却发C一个问题,也就是当size_t用作循环的时候。因Z前都是用int做@环的Q现在换成unsigned intQ也是size_tQ后Q一下子没反应过来,顺手这么写了:

 

for( size_t i = MAX - 1; i >= 0; --i)

{

//…?/p>

}

乍一看似乎没啥问题,因ؓ我@环内的代码是删除资源的,因此E序也频频崩溃?/p>

step over的结果才让h惊讶Q因为当size_t i = 0的时候,--i的结果是无穷大,而无I大则肯定满i>=0的条Ӟ所以当我们期待E序停住的时候,E序是不会停住的?/p>

修正的方式:

1、用正向遍历?/p>

2、增加判断条Ӟi>=0 && i < MAXQ,但这里也可能存在问题Q因为size_t可能被定义ؓunsigned intQ但是MAX可能是个更大的数Q比如unsigned long longQ当然这L比较不是很有意义Q或者会实现一些{换,但是如果q种情况发生的话Q程序可能还是会通过一个随机的iq入C个未知的I间中,从而造成崩溃。而且增加判断条g也得程序的q行成本提高?/p>

volnet 2010-06-30 23:51 发表评论
]]>
C++ Traitshttp://www.shnenglu.com/mymsdn/archive/2010/04/26/cpp-traits.htmlvolnetvolnetMon, 26 Apr 2010 07:31:00 GMThttp://www.shnenglu.com/mymsdn/archive/2010/04/26/cpp-traits.htmlhttp://www.shnenglu.com/mymsdn/comments/113597.htmlhttp://www.shnenglu.com/mymsdn/archive/2010/04/26/cpp-traits.html#Feedback2http://www.shnenglu.com/mymsdn/comments/commentRss/113597.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/113597.html本来惛_好写写C++ Traits的,刚刚接到interview的通知Q先贴代码,改天再议?/p>
/*
 * cpp_traits.cpp
 *
 *  Created on: 2010-4-26
 *      Author: volnet@tom.com
 */
#include <iostream>
// kinds of types for overloading.
struct undefined_type {};
struct int32_type {};
struct int64_type {};

// typedef some has_trivial_* for difference types.
template <class T>
struct type_traits {
    typedef undefined_type has_trivial_type;
};

// define the partial specialization functions.
template <>
struct type_traits<int> {
    typedef int32_type has_trivial_type;
};
template <>
struct type_traits<long> {
    typedef int64_type has_trivial_type;
};

// the dispatcher method for all kinds of types.
template <class T>
void type_detect(T& p){
    typedef typename type_traits<T>::has_trivial_type trivial_type;
    type_detect(p, trivial_type());
}

// define the functions for dispatching.
template <class T>
void type_detect(T& p, undefined_type) {
    std::cout << p;
    std::cout << " // It's a undefined type, we have NOT found the dispatcher function." << std::endl;
}
template <class T>
void type_detect(T& p, int32_type) {
    std::cout << p;
    std::cout << " // It's a int32" << std::endl;
}
template <class T>
void type_detect(T& p, int64_type) {
    std::cout << p;
    std::cout << " // It's a int64" << std::endl;
}

int main(void) {
    int int32num = 2010;
    type_detect(int32num);

    long int64num = 2010L;
    type_detect(int64num);

    std::string str = "2010";
    type_detect(str);

    std::cout << "-------end of program." << std::endl;
    return EXIT_SUCCESS;
}


volnet 2010-04-26 15:31 发表评论
]]>
[译]高效使用auto_ptrhttp://www.shnenglu.com/mymsdn/archive/2010/04/07/Using-auto_ptr-Effectively.htmlvolnetvolnetWed, 07 Apr 2010 11:08:00 GMThttp://www.shnenglu.com/mymsdn/archive/2010/04/07/Using-auto_ptr-Effectively.htmlhttp://www.shnenglu.com/mymsdn/comments/111882.htmlhttp://www.shnenglu.com/mymsdn/archive/2010/04/07/Using-auto_ptr-Effectively.html#Feedback10http://www.shnenglu.com/mymsdn/comments/commentRss/111882.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/111882.html本文来自C/C++用户日志Q?7Q?0Q,1999q?0?/i>  原文链接

大部分h都听说过auto_ptr指针Q但是ƈ非所有h都每天用它。不使用它是不明智的Q可ȝQ,因ؓauto_ptr的设计初hZ解决C++设计和编码的普遍问题Q将它用好可以写出更健壮的代码。本文指出如何正用auto_ptr以ɽE序变得安全Q以及如何避开危险Q而不是一般用auto_ptr的恶习所致的创徏间歇性和难以诊断的问题?

Z么它是一个“自动”指?

auto_ptr只是许许多多指针中的一U。许多商业库提供许多更强大的指针Q可以完成更多的事情。从可以理引用计数到提供更先进的代理服务等。应该把auto_ptr认ؓ是智能指针中的福特Escort[注释]Q一个基于简单且通用目的的智能指针,既没有小发明也没有丰富的Ҏ目的更不需要高性能Q但是能许多普通的事情做好Qƈ且能够适合日常使用的智能指针?

auto_ptr做这样一件事Q拥有一个动态分配内存对象,q且在它不再需要的时候行自动清理的职责。这里有个没有用auto_ptr指针的不安全的例子:

    // Example 1(a): Original code
    //
    void f()
    {
      T* pt( new T );

      /*...more code...*/

      delete pt;
    }

我们每天都像q样写代码,如果f()只是一个三行程序,也没做什么多余的事情Q这样做当然可以很好工作。但是如果f()没有执行delete语句Q比如程序提前返回(returnQ了Q或者在执行的时候抛出异怺Q然后就D已经分配的对象没有被删除Q因此我们就有了一个经典的内存泄漏?

一个ExampleQ?Q安全的办法是用一个“智能”的指针拥有q个指针Q当销毁的时候,删除那个被指的自动分配的对象。因个智能指针被单地用ؓ自动对象Q这是Q当它离开它的作用域的时候自动销毁对象)Q所以它被称作“自动”指针?

    // Example 1(b): Safe code, with auto_ptr
    //
    void f()
    {
      auto_ptr<T> pt( new T );

      /*...more code...*/

    } // cool: pt's destructor is called as it goes out
      // of scope, and the object is deleted automatically

现在q段代码不会再T对象上发生泄漏了Q不必在意这个方法是正常退是异帔R出,因ؓpt的析构函数将L在堆栈弹出的时候被调用。清理工作将自动q行?/p>

最后,使用auto_ptr和用内建指针一样地ҎQ如果要“收回”资源ƈ且再ơ手动管理的话,我们可以调用release()Q?/p>

    // Example 2: Using an auto_ptr
    //
    void g()
    {
      T* pt1 = new T;
      // right now, we own the allocated object

      // pass ownership to an auto_ptr
      auto_ptr<T> pt2( pt1 );

      // use the auto_ptr the same way
      // we'd use a simple pointer
      *pt2 = 12;       // same as "*pt1 = 12;"
      pt2->SomeFunc(); // same as "pt1->SomeFunc();"

      // use get() to see the pointer value
      assert( pt1 == pt2.get() );

      // use release() to take back ownership
      T* pt3 = pt2.release();

      // delete the object ourselves, since now
      // no auto_ptr owns it any more
      delete pt3;

    } // pt2 doesn't own any pointer, and so won't
      // try to delete it... OK, no double delete

最后,我们可以使用auto_ptr的reset()Ҏauto_ptr重置向另一个对象。如果auto_ptr已经获得一个对象,q个q程像是它先删除已l拥有的对象Q因此调用reset()Q就像是先销毁了auto_ptrQ然后重Z一个新的ƈ拥有该新对象Q?

    // Example 3: Using reset()
    //
    void h()
    {
      auto_ptr<T> pt( new T(1) );

      pt.reset( new T(2) );
        // deletes the first T that was
        // allocated with "new T(1)"

    } // finally, pt goes out of scope and
      // the second T is also deleted

包装指针数据成员

同样Qauto_ptr也可以被用于安全地包装指针数据成员。考虑下面使用Pimpl idiomQ或者,~译器防火墙Q的例子Q?sup>[1]

    // Example 4(a): A typical Pimpl
    //

    // file c.h
    //
    class C
    {
    public:
      C();
      ~C();
      /*...*/
    private:
      class CImpl; // forward declaration
      CImpl* pimpl_;
    };

    // file c.cpp
    //
    class C::CImpl { /*...*/ };

    C::C() : pimpl_( new CImpl ) { }
    C::~C() { delete pimpl_; }

单地_是C的私有细节被实现Z个单独的对象Q藏匿于一个指针之中。该思\要求C的构造函数负责ؓ隐藏在类内部的辅助“Pimpl”对象分配内存,q且C的析构函数负责销毁它。用auto_ptrQ我们会发现q非常容易:

    // Example 4(b): A safer Pimpl, using auto_ptr
    //

    // file c.h
    //
    class C
    {
    public:
      C();
      /*...*/
    private:
      class CImpl; // forward declaration
      auto_ptr<CImpl> pimpl_;
    };

    // file c.cpp
    //
    class C::CImpl { /*...*/ };

    C::C() : pimpl_( new CImpl ) { }

现在Q析构函C需要担心删除pimpl_指针了,因ؓauto_ptr自动处理它。事实上Q如果没有其它需要显式写析构函数的原因,我们完全不需要自定义析构函数。显Ӟq比手动理指针要容易得多,q且对象所有权包含q对象是一个不错的习惯Q这正是auto_ptr所擅长的。我们将在最后再ơ回这个例子?

所有权Q源Q以及调用?Sinks)

它本w很漂亮Qƈ且做得非常好Q从函数传入或传?span style="font-family: 'Courier New'" class="Code">auto_ptrsQ是非常有用的,比如函数的参数或者返回倹{?/p>

让我们看看ؓ什么,首先我们考虑当拷贝auto_ptr的时候会发生什么:一个auto_ptr获得一个拥有指针的对象Qƈ且在同一旉只允许有一个auto_ptr可以拥有q个对象。当你拷贝一个auto_ptr的时候,你自动将源auto_ptr的所有权Q传递给目标auto_ptrQ如果目标auto_ptr已经拥有了一个对象,q个对象先被释放。在拯完之后,只有目标auto_ptr拥有指针Qƈ且负责在合适的旉销毁它Q而源被讄为空QnullQ,q且不能再被当作原有指针的代表来使用?

例如Q?/p>

    // Example 5: Transferring ownership from
    //            one auto_ptr to another
    //
    void f()
    {
      auto_ptr<T> pt1( new T );
      auto_ptr<T> pt2;

      pt1->DoSomething(); // OK

      pt2 = pt1;  // now pt2 owns the pointer,
                  // and pt1 does not

      pt2->DoSomething(); // OK

    } // as we go out of scope, pt2's destructor
      // deletes the pointer, but pt1's does nothing

但是要避免陷阱再ơ用已l失L有权的auto_ptrQ?

    // Example 6: Never try to do work through
    //            a non-owning auto_ptr
    //
    void f()
    {
      auto_ptr<T> pt1( new T );
      auto_ptr<T> pt2;

      pt2 = pt1;  // now pt2 owns the pointer, and
                  // pt1 does not

      pt1->DoSomething();
                  // error! following a null pointer
    }

谨记于心Q我们现在看看auto_ptr如何在源和调用者之间工作。“源”这里是指一个函敎ͼ或者其它创Z个新资源的操作,q且通常移交出资源的所有权。一个“调用者”函数反转这个关p,也就是获得已l存在对象的所有权Qƈ且通常q负责释攑֮Q。而不是有一个源和调用者,q回q且利用一个秃头指针(译者注Q而不是用一个局部变量来传递这个指针)Q虽Ӟ通过一个秃头指针来获得一个资源通常很好Q?

    // Example 7: Sources and sinks
    //

    // A creator function that builds a new
    // resource and then hands off ownership.
    //
    auto_ptr<T> Source()
    {
      return auto_ptr<T>( new T );
    }

    // A disposal function that takes ownership
    // of an existing resource and frees it.
    //
    void Sink( auto_ptr<T> pt )
    {
    }

    // Sample code to exercise the above:
    auto_ptr<T> pt( Source() ); // takes ownership

注意下面的微妙的变化Q?

  1. Source()分配了一个新对象q且以一个完整安全的方式它q回l调用者,q让调用者成为指针的拥有着。即使调用者忽略了q回|昄Q如果调用者忽略了q回|你应该从来没有写q代码来删除q个对象Q对吧?Q,分配的对象也被自动安全地删除?/p>

    在本文的最后,我将演示q回一个auto_ptr是一个好习惯。让q回值包裹进一些东西比如auto_ptr通常是得函数变得强健的有效方式?

  2. Sink()通过传值的方式获得对象所有权。当执行完Sink()的时候,当离开作用域的时候,删除操作被执行Q只要Sink()没有所有权转移Q。上面所写的Sink()函数实际上ƈ没有对参数做M事情Q因此调用“Sink(pt);”就{于写了“pt.reset(0);”,但是大部分的Sink函数都将在释攑֮之前做一些工作?

不可以做的事情,以及Z么不能做

谨记Q千万不要以我之前没有提到的方式使用auto_ptrs。我已经看见q很多程序员试着用其他方式写auto_ptrs像他们在用其它对象一栗但问题是auto_ptrq不像其他对象。这里有些基本原则,我将把它们提出来以引起你的注意:

For auto_ptr, copies are NOT equivalent. Q复制auto_ptr与原来的不相等Q?

当你试着在一般的代码中?span style="font-family: 'Courier New'" class="Code">auto_ptrs的时候,它将执行拯Qƈ且没有Q何提C,拯是不相等的(l果Q它实是拯Q。看下面q段代码Q这是我在C++新闻l经常看见的Q?

    // Example 8: Danger, Will Robinson!
    //
    vector< auto_ptr<T> > v;

    /* ... */

    sort( v.begin(), v.end() );

在标准容器中使用auto_ptrsL不安全的。一些h可能要告诉你Q他们的~译器或者类库能够很好地~译它们Q而另一些h则告诉你在某一个流行的~译器的文档中看到这个例子,不要听他们的?

问题?span style="font-family: 'Courier New'" class="Code">auto_ptrq不完全W合一个可以放q容器类型的前提Q因为拷?span style="font-family: 'Courier New'" class="Code">auto_ptrs是不{h的。首先,没有M东西说明Qvector不能军_增加q制造出“扩展”的内部拯。再ơ,当你调用一个一般函数的时候,它可能会拯元素Q就像sort()那样Q函数必L能力假设拯是等L。至一个流行的排序拯“核心”的元素Q如果你试着让它?span style="font-family: 'Courier New'" class="Code">auto_ptrs一起工作的话,它将拯一份“核心”的auto_ptr对象Q因此{UL有权q且所有权转移l一个时对象)Q然后对其余的元素也采取相同的方式(从现有成员创建更多的拥有所有权的auto_ptrQ,当排序完成后Q核心元素将被销毁,q且你将遇到一个问题:q组序列里至一个auto_ptrQ也是刚才被掉包的那个核心元素Q不再拥有对象所有权Q而那个真实的指针已经随着临时对象的销毁而被删除了!

于是标准委员会回退q希望做一些能够帮助你避免q些行ؓ的事情:标准的auto_ptr被故意设计成当你希望在用标准容器的时候用它时打断你Q或者,臛_Q在大部分的标准库实C打断你)。ؓ了达到这个目的,标准委员会利用这样一个技巧:?span style="font-family: 'Courier New'" class="Code">auto_ptr's的拷贝构造函数和赋值操作符的右|rhsQ指向非帔R。因为标准容器的单元素insert()函数Q需要一个常量作为参敎ͼ因此auto_ptrs在这里就不工作了。(译者注Q右g能赋值给非常量)

使用const auto_ptr是一个好习惯

一个auto_ptr设计?span style="font-family: 'Courier New'" class="Code">const auto_ptrs不再丢失所有权Q拷贝一个const auto_ptr是违法的Q译者注Q没有这L构造函敎ͼQ实际上你可以针对它做的唯一事情是通过operator*()或者operator->()解引用它或者调用get()来获得所包含的指针的倹{这意味着我们有一个简单明了的风格来表达一个绝不丢失所有权的auto_ptrQ?

    // Example 9: The const auto_ptr idiom
    //
    const auto_ptr<T> pt1( new T );
        // making pt1 const guarantees that pt1 can
        // never be copied to another auto_ptr, and
        // so is guaranteed to never lose ownership

    auto_ptr<T> pt2( pt1 ); // illegal
    auto_ptr<T> pt3;
    pt3 = pt1;              // illegal
    pt1.release();          // illegal
    pt1.reset( new T );     // illegal

q就是我要说的cosntQ因此如果现在你要向世界证明你的auto_ptr是不会被改变q且L删除其所有权Q加上const是你要做的。const auto_ptr风格是有用的Q你必须它谨记于心?

auto_ptr以及异常安全

最后,auto_ptr对写出异常安全的代码有时候非常必要,思考下面的代码Q?/p>

    // Example 10(a): Exception-safe?
    //
    String f()
    {
      String result;
      result = "some value";
      cout << "some output";
      return result;
    }

该函数有两个可见的作用:它输Z些内容,q且q回一个String。关于异常安全的详细说明出了本文的范围[2]Q但是我们想要取得的目标是强异常安全的保障Q归lؓ保函数的原子性——如果有异常Q所有的作用一起发生或者都不发生?

虽然在例10(a)中的代码非常_yQ看h相当接近于异常安全的代码Q但仍然有一些小的瑕疵,像下面的客户代码所C:

    String theName;
    theName = f();

因ؓl果通过D回,因此String的拷贝构造函数将被调用,而拷贝赋值操作符被调用来结果拷贝到theName中。如果Q何一个拷贝失败了Qf()完成了所有它的工作以及所有它的Q务(q很好)Q但是结果是无法挽回的(哎哟我的妈呀Q?

我们可以做的更好吗,是否可以通过避免拯来避免这个问题?例如Q我们可?让函数有一个非帔R引用参数q向下面q样q回|

    // Example 10(b): Better?
    //
    void f( String& result )
    {
      cout << "some output";
      result = "some value";
    }

q看h很棒Q但实际不是q样的,q回result的赋值的函数只完成了一个功能,而将其它事情留给了我们。它仍然会出错。因此这个做法不可取?

解决q个问题的一个方法是q回一个指向动态分配指针的String对象Q但是最好的解决Ҏ是让我们做的更多Q返回一个指针包含在auto_ptrQ?

    // Example 10(c): Correct (finally!)
    //
    auto_ptr<String> f()
    {
      auto_ptr<String> result = new String;
      *result = "some value";
      cout << "some output";
      return result;  // rely on transfer of ownership;
                      // this can't throw
    }

q里是一个技巧,当我们有效隐藏所有的工作来构造第二个功能Q返回|当确保它可以被安全返回给调用者ƈ且在W一个功能(打印消息Q完成的时候没有抛出操作。我们知道一旦cout完成Q返回值将成功交到调用者手中,q且无论如何都会正确清理Q如果调用者接受返回|调用者将得到q个拯的auto_ptr临时对象的所有权Q如果调用者没有接受返回|也就是忽略返回|分配的String在临时auto_ptr被销毁的时候自动清理。这U安全扩展的代h呢?像我们l常实现的强异常安全一P强安全通常消耗一些效率(通常比较)——这里指额外的动态内存分配。但是当我们在效率和正确性之间做出选择的话Q我们通常会选择后者!

让我们养成在日常工作中用auto_ptr的习惯。auto_ptr解决了常见的问题Qƈ且能够你的代码变得更安全和健壮Q特别是它可以防止内存泄漏以及确保强安全。因为它是标准的Q因此它在不同类库和q_之间是可UL的,因此无论你在哪里使用它,它都是对的?

致谢

This article is drawn from material in the new book Exceptional C++: 47 engineering puzzles, programming problems, and exception-safety solutions by Herb Sutter, © 2000 Addison Wesley Longman Inc., which contains further detailed treatments of points touched on briefly in this article, including exception safety, the Pimpl (compiler-firewall) Idiom, optimization, const-correctness, namespaces, and other C++ design and programming topics.

注释

  1. Pimpl风格可以有效减少目构徏旉Q因为它在CU有部分改变的时候,L客户代码引vq泛的重新编译。更多关于Pimpl风格以及如何部v~译器墙Q参考这?a href="xc++.htm">Exceptional C++的条?6?0。(Addison-Wesley, 2000Q?

  2. See the article originally published in C++ Report and available on the Effective C++ CD (Scott Meyers, Addison-Wesley, 1999) and Items 8 to 19 in Exceptional C++ (Herb Sutter, Addison-Wesley, 2000).



volnet 2010-04-07 19:08 发表评论
]]>
[转]从C++的Return Value Optimization (RVO)到C#的value typehttp://www.shnenglu.com/mymsdn/archive/2010/04/06/111777.htmlvolnetvolnetTue, 06 Apr 2010 11:42:00 GMThttp://www.shnenglu.com/mymsdn/archive/2010/04/06/111777.htmlhttp://www.shnenglu.com/mymsdn/comments/111777.htmlhttp://www.shnenglu.com/mymsdn/archive/2010/04/06/111777.html#Feedback0http://www.shnenglu.com/mymsdn/comments/commentRss/111777.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/111777.html先看一D늮单的C++代码Q?
Type get(int I){
    return Type(i);
} 

Type t = get(1); 

q里Q?我们从C++的基本语义看上去Q?应该是Type(i) 调用一ơ拷贝构造函敎ͼ 在堆栈中生成一个时对象;然后Q用该对象构造返回对象;然后对这个时对象调用析构函敎ͼ在调用者方Q?用返回的临时对象调用拯构造函C初始化对象t, q回对象的析构函数在q之后, 函数q回之前调用?

所以, Type t = get(i); 应该有三个拷贝构造函数和两个析构函数的调?

可是Q?q有一U说法是Q?~译器可能会对这两个临时对象q行优化Q最l的优化l果会是只有一ơ的构造函数。因为很明显地可以看刎ͼ q里我们其实只是要用一个整数构造一个Type对象?

? g很有道理Q?

那么Q?哪一U说法对呢? 没有调查没有发a权,于是本h用VC++6.0做了实验?放了些cout<<?.在拷贝构造函数里Q观察打印的l果Q?l果却是跟我的simple, naïve的预一致。三个拷贝构造函敎ͼ 两个析构函数?

“你个弱智编译器Q脑袋进水了吧??忘了~译器没脑袋?“很明显在这个例子里我的两个临时对象都没有用的啊Q?

于是Q上|, 查资料, google一下吧Q?

下面是我查到的一些结果:

其实Q?q种对g递的优化的研IӞ q不只局限于q回倹{对下面q个例子Q?

void f(T t) { } 
void main(void){ 
    T t1;
    f(t1); 
} 

也有q种考虑?

f(T)是按g递的。语义上应该做一个复Ӟ 使得函数内部对T的改变不会媄响到原来的t1.

但是Q因为在调用f(t1)之后Q?我们没有再用t1(除了一个隐含的destructor调用)Q是否可能把复制优化掉, 直接使用t1呢?q样可以节省掉一个拷贝构造函数和一个析构函数?

可是Q?不论是对q回值的优化Q?q是对上面这U局部对象的优化Q在1995q的C++新标准草案出台前都是为标准所严格限制?(虽然有些~译器ƈ没有遵行q个标准Q?q是支持了这U“优化?

那么Q?q又是ؓ什么呢Q?

q里面涉及到一个普遍的对side-effect的担忧?

什么又是side-effect呢?

所谓side-effect是一个函数的调用与否能够对系l的状态造成区别?

int add(int i, int j){ return i+j; }是没有side-effect的,?

void set(int* p, int I, int v){ p[I]=v; }是有side-effect的。因为它改变了一个数l元素的| 而这个数l元素在函数外是可见的?

通常意义上来_ 所有的优化应该在不影响E序的可观察行ؓ的基上进行的。否则,快则快了Q?l果却和所惌的完全不同!

而C++的拷贝构造函数和析构函数又很多都是有side-effect的。如果我们的“优化”去掉了一个有side-effect的拷贝构造函数和一个析构函敎ͼ q个“优化”就有可能改变程序的可观察行为。(注意Q?我这里说的是“可能”,因ؓ“负负得正”, 两个有side-effect的函数的调用Q?在不考虑q行q行的情况下Q?也许反而不会媄响程序的可观察行为。不q, q种塞翁失马的事儿, ~译器就很难判断了)

Zq种忧虑, 1995q以前的标准Q?明确止对含有side-effect的拷贝构造函数和析构函数的优化。同Ӟ q有一些对C++扩充的提议, 考虑让程序员自己对类q行允许优化的声明?E序员可以明地告诉~译器:不错Q?我这个拷贝构造函敎ͼ 析构函数是有side-effect, 但你别管Q?管优化Q?Z事有我呢Q?

哎, side-effect真是一个让人又恨又q东西Q它使编译器的优化变得困难;加大了程序维护和调试的难度。因?functional language 把side-effect当作z水猛兽一Pq脆止。但同时Q我们又很难dside-effect. 不说E序员们更习惯于imperative 的编E方? 象数据库操作QIO操作都天然就是side-effect.

不过Q个是认为C++标准对“优化”的保守态度是有道理的。无论如何,让“优化”可以潜在地偷偷地改变程序的行ؓL让h惌v来就不舒服的?

但是Q?矛盾是对立统一的。(惛_q俺马列可得了八十多分呢Q?对这Uaggressive的“优化”的呼声是一高q一?以Stan Lippeman为首的一撮固分子Ҏ准的颠覆和和qx变的阴谋从来没有停止过?q不Q在1996q的一个风雨交加的夜晚Q?一个阴险的C++新标准草案出炉了。在q个草案里, 加入了一个名为RVO (Return Value Optimization) 的放宽对优化的限Ӟ 妄图走资本主义道路, l资本家张目的提案。其具体内容是_允许~译器对命名q的局部对象的q回q行优化Q?即拯构造函?析构函数有side-effect也在所不惜。这个提议背后所隐藏的思想是Qؓ了提高效率, 宁可冒改变程序行为的风险。宁要资本主义的苗, 不要C会M的草了!

我想Q?q样的一个罪大恶极的提案竟会被提交,应该是因为C++的值拷贝的语义的效率实在太“妈妈的”了?当你写一?Complex operator+(const Complex& c1, const Complex& c2);的时候, 竟需要调用好几次拯构造函数和析构函数Q同志们Q(沉痛圎ͼ 语重心长圎ͼC会M的生产关pȝ优越性怎么体现啊?

接下来, 当我想Google C++最新的标准Q?看RVO是否被最l采UxQ?却什么也找不C?到ANSI的网站上去, 居然要付钱才能DOWNLOAD文档?“老子在城里下馆子都不付钱Q?down你几个烂文档q要l钱Q!?

故事没有l局Q?实在是不爽?也不知是不是因ؓ标准q没有敲定, 所以VC++6 没有优化, q是VCҎ没完全遵守标准?

不过Q有一Ҏ肯定的?当写E序的时候, 最好不要依赖于RVO (有hQ?象Stan Lippeman, 又叫它NRV优化)?因ؓQ?不论Ҏ准的争论是否已经有了l果Q?实际上各个编译器的实Cq是各自为政Q?没有l一?一个叫SCOtt Meyers的家?忘了是卖什么的?pQ?如果你的E序依赖于RVO, 最好去掉这U依赖。也是_ 不管RVO到底标准不标准, 你还是不能用?不仅不能用, q得时刻警惕着RVO可能带来的程序行Z的变化?Q也不知q帮家伙瞎忙了半天到底ؓ啥!Q?

说到q里Q?倒想起了C#里一个困惑了我很久的问题。记得读C#的specification的时候, 非常不解Z么C#不允许给value type 定义析构函数?

q里Q?先简略介l一下C#里的value type (原始数据cdQ?struct cd)?

在C#里的value_typep是| 永远只能copy, 取倹{因此, 它永q是in-place的。如果你把一个value type的数据放在一个对象里Q它的生命期和那个对象相同Q如果你声明一个value type 的变量在函数中, 它的生命期就在lexical scope里?

{

  The_ValueType value;

}//value 到这里就死菜?

啊呀呀Q?q不正是我们怀늚C++的stack object吗?

在C++里,Auto_ptr, shared_ptr, 容器们, 不都是利用析构函数来理资源的吗Q?

C#QJava 虽然利用garbage collection技术来攉无用对象Q?使我们不用再担心内存的回收?但garbage collectionq不保证无用对象一定被攉Q?q不保证Dispose()函数一定被调用Q?更不保证一个对象什么时候被回收?所以对一些非内存的资源, 象数据库q接Q?|络q接Q?我们q是希望能有一个类gsmart pointer的东西来帮我们管理啊。(try-finally 虽然可以用, 但因为它影响到lexical scope, 有时用v来不那么方便Q?

于是Q?我对C#的取消value type的析构函数充满了深厚的阶U仇恨?

不过Q?现在xQ?C#的这U设计一定是惩于C++p|的教训:

   1. value type 没有拯构造函数。C#只做~省copy, 没有side-effect
   2. value type 不准有析构函数。C#有garbage collection, 析构函数的唯一用途只会是做一些side-effect象关闭数据库q接?所以取消了析构函数Q?取消了value type的side-effect.
   3. 没有了side-effect, pȝ可以L地做优化?

对以下程序:

The_Valuetype get(int I){return The_Valuetype(i);}

The_Valuetype t = get(1);

在C#里我们可以快乐地_只调用了一ơ构造函数?再没有side-effect的沙漠, 再没有难以优化的荒原Q?smart pointer望而却步, 效率之花处处开遍?I have a dream, …?/p>

转蝲自:http://gugu99.itpub.net/post/34143/466008



volnet 2010-04-06 19:42 发表评论
]]>
模板cd推断的一个小问题http://www.shnenglu.com/mymsdn/archive/2010/04/05/111629.htmlvolnetvolnetSun, 04 Apr 2010 16:28:00 GMThttp://www.shnenglu.com/mymsdn/archive/2010/04/05/111629.htmlhttp://www.shnenglu.com/mymsdn/comments/111629.htmlhttp://www.shnenglu.com/mymsdn/archive/2010/04/05/111629.html#Feedback0http://www.shnenglu.com/mymsdn/comments/commentRss/111629.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/111629.html/* * type_infer_in_const_char_array.cpp * * Created on: 2010-4-4 * Author: volnet * Ref: http://topic.csdn.net/u/20100403/16/aebc3e87-ae49-4a18-ba0b-263348b512e3.html * ShortRef: http://is.gd/be914 */ #include <stdlib.h> #include <iostream> #ifdef _MSC_VER #include <typeinfo.h> #else #include <typeinfo> #endif template <typename T> int compare(const T &v1, const T &v2) { std::cout << "invoking compare ..." << std::endl; if(v1<v2) return -1; if(v2<v1) return 1; return 0; } int main() { //error: // no matching function for call to `compare(const char[3], const char[6])' // compare("hi","world"); compare<const char*>("hi","world"); //what's the real type about "abcd"? // const char * or const char [n] ? std::cout << typeid("hi").name() << std::endl; // char const [3] std::cout << typeid("world").name() << std::endl; // char const [6] std::cout << typeid("dlrow").name() << std::endl; // char const [6] // the compiler infer the typename T is char const [6] compare("world", "dlrow"); }

volnet 2010-04-05 00:28 发表评论
]]>
指针的实玎ͼ1Q?/title><link>http://www.shnenglu.com/mymsdn/archive/2010/04/04/design_of_smart_ptr_1.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Sun, 04 Apr 2010 15:08:00 GMT</pubDate><guid>http://www.shnenglu.com/mymsdn/archive/2010/04/04/design_of_smart_ptr_1.html</guid><wfw:comment>http://www.shnenglu.com/mymsdn/comments/111621.html</wfw:comment><comments>http://www.shnenglu.com/mymsdn/archive/2010/04/04/design_of_smart_ptr_1.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/mymsdn/comments/commentRss/111621.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/mymsdn/services/trackbacks/111621.html</trackback:ping><description><![CDATA[<p>首先我们面的挑战是Q声明堆中的数据需要我们用new关键字,直到我们昄调用了delete之后Q它们才会被U除Q但问题是,我们什么时候应该移除?如果调用语句在上下行中,我们自然知道如何U除。我们知道如果对象声明在堆中Q那么在它离开它的作用域中的时候,可以自动释放Q如果我们能够用栈对象来理堆对象,在栈对象自动释放的时候,释放堆对象,׃需要显式调用delete语句了: <p>于是有了下面的做法Q应该不隄解:<pre class="gc-code"><span style="color: blue">template</span><<span style="color: blue">class </span>T> <span style="color: blue">class </span>smart_ptr { <span style="color: blue">public</span>: smart_ptr(T* t = 0) { real_ptr = t; } ~smart_ptr() { <span style="color: blue">delete </span>real_ptr; } T* <span style="color: blue">operator </span>->() <span style="color: blue">const </span>{ <span style="color: blue">return </span>real_ptr; } T& <span style="color: blue">operator </span>*() <span style="color: blue">const </span>{ <span style="color: blue">return </span>*real_ptr; } <span style="color: blue">private</span>: T* real_ptr; };</pre> <p>我们希望我们的智能指针能够像指针一样地工作Q但下面的工作方式似乎存在问题: <p>在普通的dumb指针中,以下行ؓ是正的Q?pre class="gc-code"><span style="color: blue">void </span>letUsGo(BaseClass* objPtr); DerivedClass* derivedObjPtr2 = <span style="color: blue">new </span>DerivedClass(); letUsGo(derivedObjPtr2); <span style="color: blue">delete </span>derivedObjPtr2;</pre> <p>但是Q以下代码呢Q?pre class="gc-code"><span style="color: blue">void </span>letUsSmartGo(<span style="color: blue">const </span>smart_ptr<BaseClass>& objPtr); smart_ptr<DerivedClass> smartDerivedObjPtr2(<span style="color: blue">new </span>DerivedClass()); <span style="color: green">// the smart_ptr<DerivedClass> is not inherited from the smart_ptr<BaseClass> // the compiler can't find the class to cast it, so it must cause the error. </span>letUsSmartGo(smartDerivedObjPtr2);</pre><a ></a> <p>下面的过E描qCq个变化所需要的一些支持: <p>1、error C2664: “letUsSmartGo? 不能参?1 从“smart_ptr<T>”{换ؓ“const smart_ptr<T> &?br>2、smartDerivedObjPtr2的类型:<br>    smart_ptr<DerivedClass> smartDerivedObjPtr2(new DerivedClass());<br>3、letUsSmartGo的声明:<br>    void letUsSmartGo(const smart_ptr<BaseClass>&);<br>4、问题{化ؓQ如何从smart_ptr<DerivedClass>到const smart_ptr<BaseClass>&的{变?br>5、针对letUsSmartGo的声明,可以有的实参cd包括Q?br>    const smart_ptr<BaseClass><br>    smart_ptr<BaseClass><br>    假设存在以下cd smart_derived_ptr : smart_ptr<BaseClass>Q那么smart_derived_ptr也是可以被传递的?br>6、这里存在这样一个问题:<br>    new DerivedClass() 被传递给smartDerivedObjPtr2之后QsmartDerivedObjPtr2拥有了它的指针。如果从smartDerivedObjPtr2隐式转换成另一个smart_ptr<X>后,我们需要解决的是smartDerivedObjPtr2所拥有的指针传递给smart_ptr<X>q将smartDerivedObjPtr2的内部指针清Ӟq样׃会在smartDerivedObjPtr2被销毁的时候,因ؓ调用delete real_ptrQ而它的新拯在离开作用域的时候,一样会再次调用delete real_ptrQ而此时real_ptr指向的对象已l被释放Q因此这L行ؓ是未定义的。)<br>7、因此,定义如下Ҏ卛_Q?pre class="gc-code"><span style="color: blue">template</span><<span style="color: blue">class </span>T> <span style="color: blue">class </span>smart_ptr { <span style="color: blue">public</span>: smart_ptr(T* t = 0) { std::cout << <span style="color: #a31515">"creating smart_ptr ...smart_ptr(T* t = 0)" </span><< std::endl; real_ptr = t; } <strong> <span style="color: blue">template</span><<span style="color: blue">class </span>U> smart_ptr(smart_ptr<U>& rhs) : real_ptr(rhs.real_ptr){ std::cout << <span style="color: #a31515">"creating smart_ptr ...smart_ptr(smart_ptr<U>& rhs)" </span><< std::endl; rhs.real_ptr = 0; }</strong> ~smart_ptr() { std::cout << <span style="color: #a31515">"destoring smart_ptr ..." </span><< std::endl; <span style="color: blue">delete </span>real_ptr; } T* <span style="color: blue">operator </span>->() <span style="color: blue">const </span>{ <span style="color: blue">return </span>real_ptr; } T& <span style="color: blue">operator </span>*() <span style="color: blue">const </span>{ <span style="color: blue">return </span>*real_ptr; } <span style="color: green"> </span>T* real_ptr; };</pre> <p>8、但是这里real_ptr按照习惯应该是一个私有成员,而且我们在完成该Ҏ时候,希望能够实现一U所谓的所有权转移Q也是内部的指针传递给另一个智能指针,而这应该是一个原子过E。因此,我们实现以下ҎQ?/p><pre class="gc-code"><span style="color: blue">template</span><<span style="color: blue">class </span>T> <span style="color: blue">class </span>smart_ptr { <span style="color: blue">public</span>: smart_ptr(T* t = 0) { std::cout << <span style="color: #a31515">"creating smart_ptr ...smart_ptr(T* t = 0)" </span><< std::endl; real_ptr = t; } <span style="color: blue">template</span><<span style="color: blue">class </span>U> smart_ptr(smart_ptr<U>& rhs) : real_ptr(rhs.release()){ std::cout << <span style="color: #a31515">"creating smart_ptr ...smart_ptr(smart_ptr<U>& rhs)" </span><< std::endl; } ~smart_ptr() { std::cout << <span style="color: #a31515">"destoring smart_ptr ..." </span><< std::endl; <span style="color: blue">delete </span>real_ptr; } T* <span style="color: blue">operator </span>->() <span style="color: blue">const </span>{ <span style="color: blue">return </span>real_ptr; } T& <span style="color: blue">operator </span>*() <span style="color: blue">const </span>{ <span style="color: blue">return </span>*real_ptr; } <span style="color: green">// helper </span>T* release() { T* tmp = real_ptr; real_ptr = 0; <span style="color: blue">return </span>tmp; } <span style="color: blue">private</span>: T* real_ptr; };</pre><img src ="http://www.shnenglu.com/mymsdn/aggbug/111621.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/mymsdn/" target="_blank">volnet</a> 2010-04-04 23:08 <a href="http://www.shnenglu.com/mymsdn/archive/2010/04/04/design_of_smart_ptr_1.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用事实说话,C++ ProfilerQVisual Studio 2008Q?/title><link>http://www.shnenglu.com/mymsdn/archive/2010/04/01/111307.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Thu, 01 Apr 2010 10:02:00 GMT</pubDate><guid>http://www.shnenglu.com/mymsdn/archive/2010/04/01/111307.html</guid><wfw:comment>http://www.shnenglu.com/mymsdn/comments/111307.html</wfw:comment><comments>http://www.shnenglu.com/mymsdn/archive/2010/04/01/111307.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/mymsdn/comments/commentRss/111307.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/mymsdn/services/trackbacks/111307.html</trackback:ping><description><![CDATA[<p><a href="http://www.shnenglu.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_thumb.png" width="1186" height="786"></a> </p> <p>1、设|“生成时启用C/C++代码分析”ؓ“是”,如果不设|此,E序速度出乎你的意料…?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_4.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_thumb_1.png" width="852" height="640"></a> </p> <p>2、点几Z分析?>“启动性能向导?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_6.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_thumb_2.png" width="890" height="370"></a> </p> <p>3、在“性能资源理器”中右键新徏的性能报告节点Q右键“启动ƈ启用分析功能”?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_10.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_thumb_4.png" width="658" height="262"></a> </p> <p>虽然此处有“启用分析功能”,但如果在配置里面没有q行讄Q第一ơ的试报告l果是不准的?/p> <p>4、选择两个性能报告Qctrl+鼠标Q,右键“比较性能报告”?/p> <p><a href="http://www.shnenglu.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_8.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.shnenglu.com/images/cppblog_com/mymsdn/WindowsLiveWriter/CProfilerVisualStudio2008_FD62/image_thumb_3.png" width="785" height="370"></a> </p> <p></p> <p></p> <p>用性能报告有助于提高E序的性能Qƈ且快速定位问题所在,剩下的结果就是你自己需要多观察Q分析性能报告所反映的问题了?br></p> <p>更多</p> <p>VC++ 6.0详见q里>> <a title="http://neural.cs.nthu.edu.tw/jang/mir/technicalDocument/vc6_profile/index.htm" >http://neural.cs.nthu.edu.tw/jang/mir/technicalDocument/vc6_profile/index.htm</a></p> <p>W三方工?gt;> <a title="http://www.semdesigns.com/Products/Profilers/CppProfiler.html" >http://www.semdesigns.com/Products/Profilers/CppProfiler.html</a></p><img src ="http://www.shnenglu.com/mymsdn/aggbug/111307.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/mymsdn/" target="_blank">volnet</a> 2010-04-01 18:02 <a href="http://www.shnenglu.com/mymsdn/archive/2010/04/01/111307.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ubuntu下编译boostQ附Eclipse静态链接库讄Q?/title><link>http://www.shnenglu.com/mymsdn/archive/2010/03/30/install-boost-under-boost.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Tue, 30 Mar 2010 09:17:00 GMT</pubDate><guid>http://www.shnenglu.com/mymsdn/archive/2010/03/30/install-boost-under-boost.html</guid><wfw:comment>http://www.shnenglu.com/mymsdn/comments/111019.html</wfw:comment><comments>http://www.shnenglu.com/mymsdn/archive/2010/03/30/install-boost-under-boost.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/mymsdn/comments/commentRss/111019.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/mymsdn/services/trackbacks/111019.html</trackback:ping><description><![CDATA[q不是一向|全面的向D?a href="http://www.boost.org/doc/libs/1_42_0/more/getting_started/unix- variants.html">q里</a>Qhttp://goo.gl/XcAfQ?br>q仅是一笔记。这里用<a href="http://www.boost.org/doc/libs/1_42_0/more/getting_started/unix- variants.html#easy-build-and-install">bjam方式</a>q行~译?br><ol><li>下蝲boost。(http://cdnetworks-kr-1.dl.sourceforge.net/project/boost/boost/1.42.0/boost_1_42_0.tar.bz2Q?/li><li>解压到指定文件夹Q我是将它解压到根目录下的一个sourcecode文g夹下?div class="console">    /home/volnet/sourcecode/boost_1_42_0</div></li><li>启动l端Qctrl+f2,输入“gnome-terminal”Q。生成bjam脚本?div class="console">    ./bootstrap.sh --prefix=/home/volnet/sourcecode/boost_install</div>如果不带--prefix参数的话Q?b>推荐</b>Q,默认的\径是/usr/local/include?usr/local/lib<div id="sg4wiqo" class="console">    ./bootstrap.sh</div>使用--help参数可以查看帮助Q用-h可以查看要帮助?div class="console">    ./bootstrap.sh --help</div>生成脚本bjamQ已l存在的脚本被自动备䆾?pre class="console">volnet@Ubuntu:~/sourcecode/boost_1_42_0$ ./bootstrap.sh --prefix=/home/volnet/sourcecode/boost_install/<br>Building Boost.Jam with toolset gcc... tools/jam/src/bin.linuxx86/bjam<br>Detecting Python version... 2.6<br>Detecting Python root... /usr<br>Unicode/ICU support for Boost.Regex?... /usr<br>Backing up existing Boost.Build configuration in project-config.jam.4<br>Generating Boost.Build configuration in project-config.jam...<br><br>Bootstrapping is done. To build, run:<br><br>    ./bjam<br>    <br>To adjust configuration, edit 'project-config.jam'.<br>Further information:<br><br>   - Command line help:<br>     ./bjam --help<br>     <br>   - Getting started guide: <br>     http://www.boost.org/more/getting_started/unix-variants.html<br>     <br>   - Boost.Build documentation:<br>     http://www.boost.org/boost-build2/doc/html/index.html<br><br></pre></li><li>然后是利用生成的bjam脚本~译源码了?br><div id="4iu4s44" class="console">volnet@Ubuntu:~/sourcecode/boost_1_42_0$ sudo ./bjam -a -sHAVE_ICU=1 installNote: Building Boost.Regex with Unicode/ICU support enabled    Using ICU in  /usr/include</div><ul><li>./是unix-likepȝ执行文g的前~Q这里就是指要执行bjam文g?/li><li>-a是参敎ͼ代表重新~译QRebuildQ。输?/bjam -h获得更多帮助?/li><li>-sHAVE_ICU=1Q代表支持Unicode/ICU?a >点击q里Qhttp://goo.gl/ySEeQ?/a><br><div id="oq4uoou" class="note">前提Q系l内需要安装有libicu-devQ可以在l端输入Q?br><div id="48mcs4m" class="console">sudo apt-get install libicu-dev</div></div></li><li>installQ表C安?/li><li>--cleanQ表C清理。当前语句中包含-aQ则不需要先手动清理Q否则需要先q行<div id="y4sec8w" class="console">./bjam --clean</div></li></ul></li><li>如果你执行上一步,会出现诸如:mpi的问题,多半是本机没有安装mpi。根据系l提C,你可以找到有/home/volnet/sourcecode/boost_1_42_0/tools/build/v2/user-config.jam。在文g最后跟?div class="console">using mpi ;</div>卛_。然后如果还是有mpi问题Q说明本机没有安装mpi?div class="console">sudo apt-get install mpi-default-dev</div></li></ol><br>界此应该利通过~译了。ƈ?usr/local/lib下有了boost的库了?br>下面讨论一下链接静态链接库在Eclipse里的问题?br>?a >Unix variants</a>向导里,官方提供了一个用正则表辑ּ的程序?br>在Eclipse里,新增c++ projectQƈ使用Linux C++~译器。将代码拯到文件中Q?br>因ؓ要静态链接到正则表达式的库,所以如下图所C,讄对应?.a文g路径到eclipseQ以佉K接器能够扑ֈ它?br><img src="http://www.shnenglu.com/images/cppblog_com/mymsdn/static-library-in-eclipse.png" border="0"><br><br>~译通过Q?br>Z我们的程序能够正蝲入,我们需要让我们的程序在我们的系l范围内也能够找到我们的库。这时候我们需要在讄一下。详?a >q部?/a>的相关介l?br>试E序Q?br><div id="yi84448" class="console">volnet@Ubuntu:~/workspace/boost_get_started/Debug$ ./boost_get_started < test<br>Will Success Spoil Rock Hunter?<br></div>q里test是一个文件?br><br><br> <img src ="http://www.shnenglu.com/mymsdn/aggbug/111019.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/mymsdn/" target="_blank">volnet</a> 2010-03-30 17:17 <a href="http://www.shnenglu.com/mymsdn/archive/2010/03/30/install-boost-under-boost.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>单参数构造函数的问题Qsingle-argument constructhttp://www.shnenglu.com/mymsdn/archive/2010/03/29/single-argument-construct.htmlvolnetvolnetMon, 29 Mar 2010 07:37:00 GMThttp://www.shnenglu.com/mymsdn/archive/2010/03/29/single-argument-construct.htmlhttp://www.shnenglu.com/mymsdn/comments/110879.htmlhttp://www.shnenglu.com/mymsdn/archive/2010/03/29/single-argument-construct.html#Feedback0http://www.shnenglu.com/mymsdn/comments/commentRss/110879.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/110879.html关于单一参数构造函数的问题Q主要是因ؓ单一参数被编译器用作隐式cd转换Q从而导致一些不可预期的事g的发生,请参见代码详l注释:

/*
 * single_argument_ctor.cpp
 *
 *  Created on: 2010-3-29
 *      Author: Volnet
 *      Compiler: GNU C++(version 3.4.5)
 *                MSVC CL(version 15.00.30729.01)
 */

#include <stdlib.h>
#include <iostream>
#include <sstream>

// single-argument class
class SingleArgumentClass {
private:
    int _inner;
public:
    SingleArgumentClass()
        :_inner(-1)
    {

    }
    SingleArgumentClass(int actual)
        :_inner(actual)
    {

    }
    bool operator==(const SingleArgumentClass& rhs);
    std::string str(){
        // we'd better to use boost::lexical_cast to cast.
        // #region cast
        std::stringstream strStream;
        strStream << _inner;
        std::string str;
        strStream >> str;
        // #endregion
        return str;
    }
};
bool
SingleArgumentClass::operator ==(const SingleArgumentClass& rhs){
    if(_inner == rhs._inner)
        return true;
    return false;
}

// single-argument class fixed bug by explicit keyword.
class SingleArgumentClassFixedBugByExplicitKeyword {
private:
    int _inner;
public:
    SingleArgumentClassFixedBugByExplicitKeyword()
        :_inner(-1)
    {

    }
    explicit SingleArgumentClassFixedBugByExplicitKeyword(int actual)
        :_inner(actual)
    {

    }
    bool operator==(const SingleArgumentClassFixedBugByExplicitKeyword& rhs);
    std::string str(){
        // we'd better to use boost::lexical_cast to cast.
        // #region cast
        std::stringstream strStream;
        strStream << _inner;
        std::string str;
        strStream >> str;
        // #endregion
        return str;
    }
};
bool
SingleArgumentClassFixedBugByExplicitKeyword::operator ==(const SingleArgumentClassFixedBugByExplicitKeyword& rhs){
    if(_inner == rhs._inner)
        return true;
    return false;
}

// single-argument class fixed bug by helper class.
class ActualType {
public:
    ActualType(int value):_value(value){};
    int get_value(){ return _value; }
private:
    int _value;
};
class SingleArgumentClassFixedBugByHelperClass {
private:
    int _inner;
public:
    SingleArgumentClassFixedBugByHelperClass()
        :_inner(-1)
    {

    }
    SingleArgumentClassFixedBugByHelperClass(ActualType actual)
        :_inner(actual.get_value())
    {

    }
    bool operator==(const SingleArgumentClassFixedBugByHelperClass& rhs);
    std::string str(){
        // we'd better to use boost::lexical_cast to cast.
        // #region cast
        std::stringstream strStream;
        strStream << _inner;
        std::string str;
        strStream >> str;
        // #endregion
        return str;
    }
};
bool
SingleArgumentClassFixedBugByHelperClass::operator ==(const SingleArgumentClassFixedBugByHelperClass& rhs){
    if(_inner == rhs._inner)
        return true;
    return false;
}


void Assert(bool status,
        std::string strTrue = std::string("assert result is true;"),
        std::string strFalse = std::string("assert result is false;"));
int main(void){
    SingleArgumentClass obj(3);
    std::cout << obj.str() << std::endl;

    // our purpose.
    SingleArgumentClass obj1(1);
    SingleArgumentClass obj2(1);
    Assert(obj1 == obj2, "obj1 == obj2", "obj1 != obj2");

    int i = 3;
    // warning!!!
    // obj is a SingleArgumentClass object.
    // i is a integer.
    // operator== only define the equal between two SingleArgumentClass object.
    // In fact:
    //    obj == i:
    //        1.compiler found the operator== require two SingleArgumentClass object.
    //        2.compiler try to find a cast method for casting int to SingleArgumentClass.
    //        3.compiler found it can use the SingleArguementClass.Ctor(int)
    //            to create a new SingleArgumentClass.
    //         4.compiler try to create a new SingleArgumentClass object from i.
    //        5.so it without any warning and error, but it's logical not we need.
    Assert(obj == i, "obj == i //right?", "obj != i");
    // Assert(i == obj); // Compile ERROR: no match for 'operator==' in 'i == obj'

    // it's may encounter a compile-time error.
    // GNU G++: no match for 'operator==' in 'objFixed == i'    single_argument_ctor.cpp    single_argument_ctor/src    106    C/C++ Problem
    // MSVC: 错误    1    error C2679: 二进制?=? 没有扑ֈ接受“int”类型的x作数的运符(或没有可接受的{?    {projectpath}\single_argument_ctor\src\single_argument_ctor.cpp    107    single_argument_ctor
    SingleArgumentClassFixedBugByExplicitKeyword objFixed(3);
    // Assert(objFixed == i, "objFixed == i", "objFixed != i");

    SingleArgumentClassFixedBugByHelperClass objFixedByHelper1(3);
    SingleArgumentClassFixedBugByHelperClass objFixedByHelper2(3);
    // it's may encounter a compile-time error.
    // GNU G++: no match for 'operator==' in 'objFixedAuto1 == i'    single_argument_ctor.cpp    single_argument_ctor/src    158    C/C++ Problem
    // MSVC: 错误    1    error C2679: 二进制?=? 没有扑ֈ接受“int”类型的x作数的运符(或没有可接受的{?    {projectpath}\single_argument_ctor\src\single_argument_ctor.cpp    163    single_argument_ctor
    // Assert(objFixedByHelper1 == i);
}
void Assert(bool status,
        std::string strTrue, std::string strFalse)
{
    std::cout << (status  strTrue : strFalse) << std::endl;
}

解决ҎQ?/p>

1、explicit关键字,在单参数构造函数前使用explicit参数Q可以避免单参数构造函数被用于隐式转换?/p>

2、利用中间类的方式,详见代码“SingleArgumentClassFixedBugByHelperClass相关部分”。如果编译器不支持解x?Q则使用此方法。上面代码所提及的两ƾ主编译器均支持explicit关键字?/p>

volnet 2010-03-29 15:37 发表评论
]]>
[C++]namespace&amp;using keywordhttp://www.shnenglu.com/mymsdn/archive/2010/03/29/namespace-using-keywords.htmlvolnetvolnetMon, 29 Mar 2010 05:28:00 GMThttp://www.shnenglu.com/mymsdn/archive/2010/03/29/namespace-using-keywords.htmlhttp://www.shnenglu.com/mymsdn/comments/110846.htmlhttp://www.shnenglu.com/mymsdn/archive/2010/03/29/namespace-using-keywords.html#Feedback0http://www.shnenglu.com/mymsdn/comments/commentRss/110846.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/110846.html

有时候我们可以用namespace来组l命名空间?/p>

有时候我们又希望一些较深层ơ的cd成我们比较容易访问的对象?/p>

下面的代码提供了一U简单的CZ来满L需求?/p>

1、用namespace来组l各个类的层U关pR?/p>

2、用using关键字,深层次l构暴露到较外层?/p>

//============================================================================
// Name        : namespace.cpp
// Author      : Volnet
// Version     :
// Copyright   : reserve by volnet@tom.com
// Description : namespace in C++, Ansi-style
//============================================================================

#include <iostream>

namespace volnet {
    namespace extensions {
        class _Console {
        public:
            void WriteLine(std::string);
        };
    }
    using extensions::_Console;
}
using namespace volnet;
_Console Console;

void
_Console::WriteLine(std::string s) {
    std::cout << s << std::endl;
}

using namespace std;

int main() {
    Console.WriteLine(std::string("I'm volnet!"));
    return 0;
}


volnet 2010-03-29 13:28 发表评论
]]>
boost::tuplehttp://www.shnenglu.com/mymsdn/archive/2010/03/25/110537.htmlvolnetvolnetThu, 25 Mar 2010 09:46:00 GMThttp://www.shnenglu.com/mymsdn/archive/2010/03/25/110537.htmlhttp://www.shnenglu.com/mymsdn/comments/110537.htmlhttp://www.shnenglu.com/mymsdn/archive/2010/03/25/110537.html#Feedback0http://www.shnenglu.com/mymsdn/comments/commentRss/110537.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/110537.html
boost::tuple<derived> tup4;
boost::tuple<base> tup5;
tup5 = tup4;
tup4.get<0>().test();
tup5.get<0>().test(); // 丢失多态?br>
derived d;
boost::tuple<derived*> tup6(&d);
boost::tuple<base*> tup7;
tup7 = tup6;
tup6.get<0>()->test();
tup7.get<0>()->test(); // 恢复多态性(Ҏ1Q?

boost::tuple<derived&> tup8(d);
boost::tuple<base&> tup9(tup8);

// tup9 = tup8; 不能使用该方法,因ؓ无法对引用赋倹{?
tup8.get<0>().test(); tup9.get<0>().test(); // 恢复多态性(Ҏ2Q?/span>
/*
 * tuple.cpp
 *
 *  Created on: 2010-3-25
 *      Author: GoCool
 */
#include <stdlib.h>
#include <iostream>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include "../header/baseClass.h"

using namespace std;
class X {
  X();
public:
  X(std::string){}
};
class Y {
  Y(const Y&);
public:
  Y(){}
};
class A {
};
bool operator==(A, A) { std::cout << "All the same to me..."; return true; }
void f(int i);

void cut_off_rule(void);
int main(void){
    // add a new tuple
    boost::tuple<int,double,std::string>   triple(42, 3.14, "My first tuple!");
    int a = triple.get<0>();
    ++a;
    cout << a << endl;
    cout << triple << endl;

    cut_off_rule();

    boost::tuple<int, double> pair = boost::make_tuple(21, 22.5);
    cout << pair << endl;

    cut_off_rule();

    int pair_element_1 = -1;
    double pair_element_2 = -1;
    boost::tie(pair_element_1, pair_element_2) = pair;

    cout << pair_element_1 << "," << pair_element_2 << endl;

    cut_off_rule();

    boost::tuple<int,std::string,derived> tup1(-5,"Tuples");
    boost::tuple<unsigned int,std::string,base> tup2;
    tup2=tup1;
    tup2.get<2>().test();
    std::cout << "Interesting value: " << tup2.get<0>() << '\n';
    const boost::tuple<double,std::string,base> tup3(tup2);
    // Description    Resource    Path    Location    Type
    // assignment of read-only location    tuple.cpp    boost_tuple/src    45    C/C++ Problem
    // tup3.get<0>()=3.14;

    cut_off_rule();

    boost::tuple<X,X,X> obj = boost::tuple<X,X,X>(string("Jaba"), string("Daba"), string("Duu")); // ok

    cut_off_rule();

    double dNum = 5;
    boost::tuple<double&> numTuple(dNum);               // ok

    // boost::tuple<double&>(dNum+3.14);          // error: cannot initialize
                                    // non-const reference with a temporary

    boost::tuple<const double&>(dNum+3.14);    // ok, but dangerous:
                                    // the element becomes a dangling reference
    cut_off_rule();

    // char arr[2] = {'a', 'b'};
    // boost::tuple<char[2]>(arr); // error, arrays can not be copied
    // boost::tuple<char[2], Y>(arr, Y()); // error, neither arrays nor Y can be copied

    boost::tuple<char[2], Y>();       // ok

    cut_off_rule();

    boost::tuple<void (*)(int)> pFTuple1 = boost::make_tuple(&f);
    pFTuple1.get<0>()(10);

    boost::tuple<void (*)(int)> pFTuple2 = boost::make_tuple(boost::ref(f));
    pFTuple2.get<0>()(20);

    boost::tuple<void (&)(int)> pFTuple3(f);
    pFTuple3.get<0>()(30);

    boost::tuple<boost::tuple<void (&)(int)> > pFTuple4(f);
    pFTuple4.get<0>().get<0>()(40);

    cut_off_rule();

    // boost::tuple<int, char> stdPairToTuple = std::make_pair(1, 'a');

    cut_off_rule();

    boost::tuple<std::string, int, A> t1(std::string("same?"), 2, A());
    boost::tuple<std::string, long> t2(std::string("same?"), 2);
    boost::tuple<std::string, long> t3(std::string("different"), 3);
    // t1 == t2;        // true

    cut_off_rule();

    int i; char c;
    boost::tie(i, c) = std::make_pair(1, 'a');
    cout << i << " " << c << endl;

    cut_off_rule();

    boost::tie(boost::tuples::ignore, c) = std::make_pair(1, 'a');
    cout << c << endl;

    cut_off_rule();

    int myX = -1;
    double myY = -2;
    boost::tuple<int, double> f2(2);
    boost::tie(myX, myY) = f2; // #2
    cout << "myX = " << myX << ", myY = " <<myY << endl;
}
void cut_off_rule(void) {
    cout << "-----------------------------------" << endl;
}

void f(int i) {
    cout << "f(" << i << ")" << endl;
}


tuple是boost库中一个类似标准std::pair库库Q但pair只能支持两种元素Q而tuple则可以支持大于两U的?/p>

更多详解Q?a title="http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html" >http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html

以下内容直接引自原文Q?/p>


 

Boost C++ LibrariesBoost C++ Libraries

?..one of the most highly regarded and expertly designed C++ library projects in the world.??Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

C++ 
Boost

The Boost Tuple Library

A tuple (or n-tuple) is a fixed size collection of elements. Pairs, triples, quadruples etc. are tuples. In a programming language, a tuple is a data object containing other objects as elements. These element objects may be of different types.

Tuples are convenient in many circumstances. For instance, tuples make it easy to define functions that return more than one value.

Some programming languages, such as ML, Python and Haskell, have built-in tuple constructs. Unfortunately C++ does not. To compensate for this "deficiency", the Boost Tuple Library implements a tuple construct using templates.

Table of Contents

  1. Using the library
  2. Tuple types
  3. Constructing tuples
  4. Accessing tuple elements
  5. Copy construction and tuple assignment
  6. Relational operators
  7. Tiers
  8. Streaming
  9. Performance
  10. Portability
  11. Acknowledgements
  12. References
More details

Advanced features (describes some metafunctions etc.).

Rationale behind some design/implementation decisions.

Using the library

To use the library, just include:

#include "boost/tuple/tuple.hpp"

Comparison operators can be included with:

#include "boost/tuple/tuple_comparison.hpp"

To use tuple input and output operators,

#include "boost/tuple/tuple_io.hpp"

Both tuple_io.hpp and tuple_comparison.hpp include tuple.hpp.

All definitions are in namespace ::boost::tuples, but the most common names are lifted to namespace ::boost with using declarations. These names are: tuple, make_tuple, tie and get. Further, ref and cref are defined directly under the ::boost namespace.

Tuple types

A tuple type is an instantiation of the tuple template. The template parameters specify the types of the tuple elements. The current version supports tuples with 0-10 elements. If necessary, the upper limit can be increased up to, say, a few dozen elements. The data element can be any C++ type. Note that void and plain function types are valid C++ types, but objects of such types cannot exist. Hence, if a tuple type contains such types as elements, the tuple type can exist, but not an object of that type. There are natural limitations for element types that cannot be copied, or that are not default constructible (see 'Constructing tuples' below).

For example, the following definitions are valid tuple instantiations (A, B and C are some user defined classes):

tuple<int>
tuple<double&, const double&, const double, double*, const double*>
tuple<A, int(*)(char, int), B(A::*)(C&), C>
tuple<std::string, std::pair<A, B> >
tuple<A*, tuple<const A*, const B&, C>, bool, void*>

Constructing tuples

The tuple constructor takes the tuple elements as arguments. For an n-element tuple, the constructor can be invoked with k arguments, where 0 <= k <= n. For example:

tuple<int, double>() 
tuple<int, double>(1)
tuple<int, double>(1, 3.14)

If no initial value for an element is provided, it is default initialized (and hence must be default initializable). For example.

class X {
X();
public:
X(std::string);
};

tuple<X,X,X>() // error: no default constructor for X
tuple<X,X,X>(string("Jaba"), string("Daba"), string("Duu")) // ok

In particular, reference types do not have a default initialization:

tuple<double&>()                // error: reference must be 
// initialized explicitly

double d = 5;
tuple<double&>(d) // ok

tuple<double&>(d+3.14) // error: cannot initialize
// non-const reference with a temporary

tuple<const double&>(d+3.14) // ok, but dangerous:
// the element becomes a dangling reference

Using an initial value for an element that cannot be copied, is a compile time error:

class Y { 
Y(const Y&);
public:
Y();
};

char a[10];

tuple<char[10], Y>(a, Y()); // error, neither arrays nor Y can be copied
tuple<char[10], Y>(); // ok

Note particularly that the following is perfectly ok:

Y y;
tuple<char(&)[10], Y&>(a, y);

It is possible to come up with a tuple type that cannot be constructed. This occurs if an element that cannot be initialized has a lower index than an element that requires initialization. For example: tuple<char[10], int&>.

In sum, the tuple construction is semantically just a group of individual elementary constructions.

The make_tuple function

Tuples can also be constructed using the make_tuple (cf. std::make_pair) helper functions. This makes the construction more convenient, saving the programmer from explicitly specifying the element types:

tuple<int, int, double> add_multiply_divide(int a, int b) {
return make_tuple(a+b, a*b, double(a)/double(b));
}

By default, the element types are deduced to the plain non-reference types. E.g.:

void foo(const A& a, B& b) { 
...
make_tuple(a, b);

The make_tuple invocation results in a tuple of type tuple<A, B>.

Sometimes the plain non-reference type is not desired, e.g. if the element type cannot be copied. Therefore, the programmer can control the type deduction and state that a reference to const or reference to non-const type should be used as the element type instead. This is accomplished with two helper template functions: ref and cref. Any argument can be wrapped with these functions to get the desired type. The mechanism does not compromise const correctness since a const object wrapped with ref results in a tuple element with const reference type (see the fifth example below). For example:

A a; B b; const A ca = a;
make_tuple(cref(a), b); // creates tuple<const A&, B>
make_tuple(ref(a), b); // creates tuple<A&, B>
make_tuple(ref(a), cref(b)); // creates tuple<A&, const B&>
make_tuple(cref(ca)); // creates tuple<const A&>
make_tuple(ref(ca)); // creates tuple<const A&>

Array arguments to make_tuple functions are deduced to reference to const types by default; there is no need to wrap them with cref. For example:

make_tuple("Donald", "Daisy");

This creates an object of type tuple<const char (&)[7], const char (&)[6]> (note that the type of a string literal is an array of const characters, not const char*). However, to get make_tuple to create a tuple with an element of a non-const array type one must use the ref wrapper.

Function pointers are deduced to the plain non-reference type, that is, to plain function pointer. A tuple can also hold a reference to a function, but such a tuple cannot be constructed with make_tuple (a const qualified function type would result, which is illegal):

void f(int i);
...
make_tuple(&f); // tuple<void (*)(int)>
...

volnet:
boost::tuple<void (&)(int)> pFTuple3(f);

pFTuple3.get<0>()(30);

tuple<tuple<void (&)(int)> > a(f) // ok
make_tuple(f); // not ok

Accessing tuple elements

Tuple elements are accessed with the expression:

t.get<N>()

or

get<N>(t)

where t is a tuple object and N is a constant integral expression specifying the index of the element to be accessed. Depending on whether t is const or not, get returns the Nth element as a reference to const or non-const type. The index of the first element is 0 and thus N must be between 0 and k-1, where k is the number of elements in the tuple. Violations of these constraints are detected at compile time. Examples:

double d = 2.7; A a;
tuple<int, double&, const A&> t(1, d, a);
const tuple<int, double&, const A&> ct = t;
...
int i = get<0>(t); i = t.get<0>(); // ok
int j = get<0>(ct); // ok
get<0>(t) = 5; // ok
get<0>(ct) = 5; // error, can't assign to const
...
double e = get<1>(t); // ok
get<1>(t) = 3.14; // ok
get<2>(t) = A(); // error, can't assign to const
A aa = get<3>(t); // error: index out of bounds
...
++get<0>(t); // ok, can be used as any variable

Note! The member get functions are not supported with MS Visual C++ compiler. Further, the compiler has trouble with finding the non-member get functions without an explicit namespace qualifier. Hence, all get calls should be qualified as: tuples::get<N>(a_tuple) when writing code that should compile with MSVC++ 6.0.

Copy construction and tuple assignment

A tuple can be copy constructed from another tuple, provided that the element types are element-wise copy constructible. Analogously, a tuple can be assigned to another tuple, provided that the element types are element-wise assignable. For example:

class A {};
class B : public A {};
struct C { C(); C(const B&); };
struct D { operator C() const; };
tuple<char, B*, B, D> t;
...
tuple<int, A*, C, C> a(t); // ok
a = t; // ok

In both cases, the conversions performed are: char -> int, B* -> A* (derived class pointer to base class pointer), B -> C (a user defined conversion) and D -> C (a user defined conversion).

Note that assignment is also defined from std::pair types:

tuple<float, int> a = std::make_pair(1, 'a');

volnet:(Eclipse with MinGW g++
conversion from `std::pair<int, char>' to non-scalar type `boost::tuples::tuple<float, int, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type>' requested

Relational operators

Tuples reduce the operators ==, !=, <, >, <= and >= to the corresponding elementary operators. This means, that if any of these operators is defined between all elements of two tuples, then the same operator is defined between the tuples as well. The equality operators for two tuples a and b are defined as:

  • a == b iff for each i: ai == bi
  • a != b iff exists i: ai != bi

The operators <, >, <= and >= implement a lexicographical ordering.

Note that an attempt to compare two tuples of different lengths results in a compile time error. Also, the comparison operators are "short-circuited": elementary comparisons start from the first elements and are performed only until the result is clear.

Examples:

tuple<std::string, int, A> t1(std::string("same?"), 2, A());
tuple<std::string, long, A> t2(std::string("same?"), 2, A());
tuple<std::string, long, A> t3(std::string("different"), 3, A());

bool operator==(A, A) { std::cout << "All the same to me..."; return true; }

t1 == t2; // true
t1 == t3; // false, does not print "All the..."

Tiers

Tiers are tuples, where all elements are of non-const reference types. They are constructed with a call to the tie function template (cf. make_tuple):

int i; char c; double d; 
...
tie(i, c, a);

The above tie function creates a tuple of type tuple<int&, char&, double&>. The same result could be achieved with the call make_tuple(ref(i), ref(c), ref(a)).

A tuple that contains non-const references as elements can be used to 'unpack' another tuple into variables. E.g.:

int i; char c; double d; 
tie(i, c, d) = make_tuple(1,'a', 5.5);
std::cout << i << " " << c << " " << d;

This code prints 1 a 5.5 to the standard output stream. A tuple unpacking operation like this is found for example in ML and Python. It is convenient when calling functions which return tuples.

The tying mechanism works with std::pair templates as well:

int i; char c;
tie(i, c) = std::make_pair(1, 'a');
Ignore

There is also an object called ignore which allows you to ignore an element assigned by a tuple. The idea is that a function may return a tuple, only part of which you are interested in. For example (note, that ignore is under the tuples subnamespace):

char c;
tie(tuples::ignore, c) = std::make_pair(1, 'a');

Streaming

The global operator<< has been overloaded for std::ostream such that tuples are output by recursively calling operator<< for each element.

Analogously, the global operator>> has been overloaded to extract tuples from std::istream by recursively calling operator>> for each element.

The default delimiter between the elements is space, and the tuple is enclosed in parenthesis. For Example:

tuple<float, int, std::string> a(1.0f,  2, std::string("Howdy folks!");

cout << a;

outputs the tuple as: (1.0 2 Howdy folks!)

The library defines three manipulators for changing the default behavior:

  • set_open(char) defines the character that is output before the first element.
  • set_close(char) defines the character that is output after the last element.
  • set_delimiter(char) defines the delimiter character between elements.

Note, that these manipulators are defined in the tuples subnamespace. For example:

cout << tuples::set_open('[') << tuples::set_close(']') << tuples::set_delimiter(',') << a; 

outputs the same tuple a as: [1.0,2,Howdy folks!]

The same manipulators work with operator>> and istream as well. Suppose the cin stream contains the following data:

(1 2 3) [4:5]

The code:

tuple<int, int, int> i;
tuple<int, int> j;

cin >> i;
cin >> tuples::set_open('[') >> tuples::set_close(']') >> tuples::set_delimiter(':');
cin >> j;

reads the data into the tuples i and j.

Note that extracting tuples with std::string or C-style string elements does not generally work, since the streamed tuple representation may not be unambiguously parseable.

Performance

All tuple access and construction functions are small inlined one-liners. Therefore, a decent compiler can eliminate any extra cost of using tuples compared to using hand-written tuple like classes. Particularly, with a decent compiler there is no performance difference between this code:

class hand_made_tuple { 
A a; B b; C c;
public:
hand_made_tuple(const A& aa, const B& bb, const C& cc)
: a(aa), b(bb), c(cc) {};
A& getA() { return a; };
B& getB() { return b; };
C& getC() { return c; };
};

hand_made_tuple hmt(A(), B(), C());
hmt.getA(); hmt.getB(); hmt.getC();

and this code:

tuple<A, B, C> t(A(), B(), C());
t.get<0>(); t.get<1>(); t.get<2>();

Note, that there are widely used compilers (e.g. bcc 5.5.1) which fail to optimize this kind of tuple usage.

Depending on the optimizing ability of the compiler, the tier mechanism may have a small performance penalty compared to using non-const reference parameters as a mechanism for returning multiple values from a function. For example, suppose that the following functions f1 and f2 have equivalent functionalities:

void f1(int&, double&);
tuple<int, double> f2();

Then, the call #1 may be slightly faster than #2 in the code below:

int i; double d;
...
f1(i,d); // #1
tie(i,d) = f2(); // #2

volnet:
int myX = -1;
double myY = -2;
boost::tuple<int, double> f2(2);
boost::tie(myX, myY) = f2; // #2
cout << "myX = " << myX << ", myY = " <<myY << endl;

See [1, 2] for more in-depth discussions about efficiency.

Effect on Compile Time

Compiling tuples can be slow due to the excessive amount of template instantiations. Depending on the compiler and the tuple length, it may be more than 10 times slower to compile a tuple construct, compared to compiling an equivalent explicitly written class, such as the hand_made_tuple class above. However, as a realistic program is likely to contain a lot of code in addition to tuple definitions, the difference is probably unnoticeable. Compile time increases between 5 and 10 percent were measured for programs which used tuples very frequently. With the same test programs, memory consumption of compiling increased between 22% to 27%. See [1, 2] for details.

Portability

The library code is(?) standard C++ and thus the library works with a standard conforming compiler. Below is a list of compilers and known problems with each compiler:

Compiler
Problems

gcc 2.95
-

edg 2.44
-

Borland 5.5
Can't use function pointers or member pointers as tuple elements

Metrowerks 6.2
Can't use ref and cref wrappers

MS Visual C++
No reference elements (tie still works). Can't use ref and cref wrappers

Acknowledgements

Gary Powell has been an indispensable helping hand. In particular, stream manipulators for tuples were his idea. Doug Gregor came up with a working version for MSVC, David Abrahams found a way to get rid of most of the restrictions for compilers not supporting partial specialization. Thanks to Jeremy Siek, William Kempf and Jens Maurer for their help and suggestions. The comments by Vesa Karvonen, John Max Skaller, Ed Brey, Beman Dawes, David Abrahams and Hartmut Kaiser helped to improve the library. The idea for the tie mechanism came from an old usenet article by Ian McCulloch, where he proposed something similar for std::pairs.

References

[1] Järvi J.: Tuples and multiple return values in C++, TUCS Technical Report No 249, 1999.

[2] Järvi J.: ML-Style Tuple Assignment in Standard C++ - Extending the Multiple Return Value Formalism, TUCS Technical Report No 267, 1999.

[3] Järvi J.:Tuple Types and Multiple Return Values, C/C++ Users Journal, August 2001.


Last modified 2003-09-07

© Copyright Jaakko Järvi 2001. Permission to copy, use, modify, sell and distribute this software and its documentation is granted provided this copyright notice appears in all copies. This software and its documentation is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.



 



volnet 2010-03-25 17:46 发表评论
]]>
C语言位域http://www.shnenglu.com/mymsdn/archive/2009/12/30/c-bit-field.htmlvolnetvolnetTue, 29 Dec 2009 17:02:00 GMThttp://www.shnenglu.com/mymsdn/archive/2009/12/30/c-bit-field.htmlhttp://www.shnenglu.com/mymsdn/comments/104425.htmlhttp://www.shnenglu.com/mymsdn/archive/2009/12/30/c-bit-field.html#Feedback0http://www.shnenglu.com/mymsdn/comments/commentRss/104425.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/104425.html
 1 #include <stdio.h>
 2 typedef struct _SimpleType1 {
 3     int Variable1;    //4bytes(32bits)
 4     int Variable2;    //4bytes(32bits)
 5     int Variable3;    //4bytes(32bits)
 6     int Variable4;    //4bytes(32bits)
 7 } SimpleType1;
 8 
 9 typedef struct _ComplexType1 {
10     int Variable1 : 8;    //1bytes(8bits)
11     int Variable2 : 8;    //1bytes(8bits)
12     int Variable3 : 8;    //1bytes(8bits)
13     int Variable4 : 8;    //1bytes(8bits)
14 } ComplexType1;
15 
16 typedef struct _ComplexType2 {
17     int Variable1 : 8;    //1bytes(8bits)
18     int Variable2 : 8;    //1bytes(8bits)
19     int Variable3 : 8;    //1bytes(8bits)
20     int Variable4 : 8;    //1bytes(8bits)
21     int Variable5 : 1;    //0.125bytes(1bits) but the it also hold 32bits 
22 } ComplexType2;
23 
24 int main(void){
25     printf("sizeof SimpleType1 = %d\n"sizeof(SimpleType1));
26     printf("sizeof ComplexType1 = %d\n"sizeof(ComplexType1));
27     printf("sizeof ComplexType2 = %d\n"sizeof(ComplexType2));
28 }
l果Q?br>sizeof SimpleType1 = 16
sizeof ComplexType1 = 4
sizeof ComplexType2 = 8



volnet 2009-12-30 01:02 发表评论
]]>
关于U程同步的一些ȝQ用h?内核模式Q?/title><link>http://www.shnenglu.com/mymsdn/archive/2009/12/26/about-multithread-sync.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Fri, 25 Dec 2009 21:53:00 GMT</pubDate><guid>http://www.shnenglu.com/mymsdn/archive/2009/12/26/about-multithread-sync.html</guid><wfw:comment>http://www.shnenglu.com/mymsdn/comments/104111.html</wfw:comment><comments>http://www.shnenglu.com/mymsdn/archive/2009/12/26/about-multithread-sync.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/mymsdn/comments/commentRss/104111.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/mymsdn/services/trackbacks/104111.html</trackback:ping><description><![CDATA[<p><h3>自旋锁同?/h3><ol><li>一般是Z内核态下各个zN函数之间做同步作用的?/li><li>原理是(单CPUQ将IRQL从Y件中断提升到g中断。PASSIVE_LEVEL->DISPATCH_LEVEL。因为在DISPATCH_LEVEL中是不会出现U程切换的(只有高别能打断低别,而低U别不能打断高别)?/li><li>因ؓ分页内存导致如果线E切换的时候会引v分页数据交换Q数据交换是通过引发|障来实现的,而页故障是不允许出现在DISPATCH_LEVEL中的Q否则将引vpȝ崩溃QPASSIVE_LEVEL则允许)。驱动程序的StartIO例程、DPC例程、中断服务例E都q行在DISPATCH_LEVEL或者更高的IRQL。因此这些例E不能用分内存,否则导致系l崩溃?/li><li>自旋锁在不同IRP之间同步的时候,则需要放在DeviceExtension中传递?/li></ol></p><p><h3>互锁</h3><ol><li>cM于number++; //汇编后将不止一条语句,非原子操作number--; //同上因ؓ语句会变成多句,在线E切换的时候,两个U程下的该例E将会交l在一h行,D错误。可以:<div id="qu8oai6" class="gc-code">先加?br />number++;<br />解锁<br />再加?br />number--;<br />解锁<br /></div>来实C句话的同步(按指定顺序执行,而不受到U程切换的媄响)加锁解锁可以使用自旋?/li><li>在系l中提供了Interlocked***/ExInterlocked***实现</li></ol></p><p><h3>信号灯同?/h3><ol><li>U程1关闭信号灯,以至于用Wait****的时候,当前U程处于暂停状态?/li><li>U程2的作用就是在执行l束后,点亮信号灯(增加计数器)。当U程切换回来的时候,U程1因数器不是0而信号灯处于激zȝ态,从而l执行线E??/li></ol></p><p><h3>事g的同?/h3>Q不能递归获取互斥体)<ol><li>ȝE在辅助U程上设|了事gQ如果不使用Wait**{待事gq回Q则ȝE可能直接执行完毕了Q而导致辅助线E还在执行?/li><li>使用Wait****可以使主U程{待事g执行完成?/li></ol></p><p><h3>互斥体同?/h3>Q允讔R归获取互斥体(得到互斥体的U程q可以再ơ获得这个互斥体Q或者说互斥体对于已l获得互斥体的线E不产生“互斥”关系Q)<ol><li>创徏一个互斥体对象Q将互斥体对象传递给多个U程?/li><li>在每个线E操作的步骤中,调用Wait*****Q如果互斥体处于Ȁz(内部l护一个计数器Q,则l执行后l代码,q在调用l束后恢复互斥体Release****Q这样当别的U程试图使用互斥体后面的代码的时候,因ؓ互斥体状态未Ȁz,则无法l执行代码?/li></ol></p><p><h3>快速互斥体同步</h3><ol><li>与互斥体同步cMQ唯一区别是不允许递归获取互斥?/li></ol></p><img src ="http://www.shnenglu.com/mymsdn/aggbug/104111.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/mymsdn/" target="_blank">volnet</a> 2009-12-26 05:53 <a href="http://www.shnenglu.com/mymsdn/archive/2009/12/26/about-multithread-sync.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何~译TrueCrypt源码http://www.shnenglu.com/mymsdn/archive/2009/12/23/how-to-complie-TrueCrypt-63a.htmlvolnetvolnetWed, 23 Dec 2009 15:47:00 GMThttp://www.shnenglu.com/mymsdn/archive/2009/12/23/how-to-complie-TrueCrypt-63a.htmlhttp://www.shnenglu.com/mymsdn/comments/103863.htmlhttp://www.shnenglu.com/mymsdn/archive/2009/12/23/how-to-complie-TrueCrypt-63a.html#Feedback9http://www.shnenglu.com/mymsdn/comments/commentRss/103863.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/103863.html相关配置
       
  • Intel x86 Core 2 Duo
  •    
  • Windows 7 Ultimate x86 version
  •    
  • Windows Driver Develop Kit 7600.16385.0
  •    
  • TrueCrypt 6.3a Source.zip
  •    
  • Microsoft Visual Studio 2008 SP1 (VC++ 2008)
  •    
  • Microsoft Visual Studio VC++ 1.52
  •    
  • NASM version 2.07 compiled on Jul 19 2009
  •    
  • gzip 1.2.4 Win32 (02 Dec 97)
  •    
  • ......

配置TrueCrypt

  1. 下蝲MSVC++ 1.52Q安装在C盘下QC:\MSVC
  2. 下蝲NASMQ也安装在C盘下QC:\NASM
    http://www.nasm.us/pub/nasm/releasebuilds/2.07/win32/
  3. 下蝲GZIPQ也安装在C盘下QC:\gzip
  4. 下蝲q安装WINDDKQhttp://www.microsoft.com/whdc/DevTools/WDK/WDKpkg.mspx
    我将它们安装在D盘,路径QD:\WinDDK
  5. 讄pȝ变量Q(WIN7Q控刉板\所有控刉杉K\pȝ\高pȝ讄\环境变量Q:pȝ变量中,新增Q?br />变量1QMSVC16_ROOT    |C:\MSVC
    变量2QWINDDK_ROOT    |D:\WinDDK\7600.16385.0
    其中7600.16385.0为WinDDK的第二目录名,同时也是版本P7600是Windows7的发行版本号?br />双击变量QPATHQ在其值的末尾补上QC:\NASM;C:\gzip
    目的是ؓ了让我们可以直接在命令行实用nasm以及gzip作ؓ命o行?br />
  6. 下蝲PKCS11Q三个文Ӟ右键另存为即可?br />http://svn.openvpn.net/projects/openvpn/test/time/openvpn/pkcs11-headers/
    三个文Ӟpkcs11.h、pkcs11f.h、pkcs11t.hQ拷贝到源码下的Common文g夹下Q我的源码放在D盘根目录Q三个源码我放?#8220;D:\TrueCrypt\Common”文g夹中?br />
  7. ~译Q会发现有两个错误?br />CKR_NEW_PIN_MODE和CKR_NEXT_OTP未定义,补充定义一下即可?br />在d:\TrueCrypt\Common\pkcs11t.h文g里(h据您自己的\径进行复Ӟ
    q里它们设|ؓQ?br />
    #define CKR_NEW_PIN_MODE      0x000001B0
    #define CKR_NEXT_OTP          0x000001B1
    我的Ҏ是找到实用它的语句附q的同类语句Q找到相同的定义Q在其下Ҏ加?br />比如Q?br />
                TC_TOKEN_ERR (CKR_MUTEX_NOT_LOCKED)
                TC_TOKEN_ERR (CKR_NEW_PIN_MODE)
                TC_TOKEN_ERR (CKR_NEXT_OTP)
    q三句话攑֜一P后两句有问题Q但W一句正常,则查找CKR_MUTEX_NOT_LOCKED的存放位|,在其下方d如上两句Q其中定义的值参?br />http://www.cryptsoft.com/pkcs11doc/STANDARD/include/v220/otp-pkcs11.hQ这里的值只不过是一U错误码Q只要它不重复,可以了?br />
  8. 再编译,可能会遇C些警告:
    1. nasm.exe正在停止Q而因为没有正执行,又导?#8220;fatal error LNK1136: invalid or corrupt file”错误?br />遇到q个可能是因Z的nasm正在试图~译ase_amdX64.asm文gQ而nasm?4位的asm~译对你可能意义不大Qv码对我而言是这LQ于是,我就它转成~译x86体系架构的,也许是因为参数配|的问题Q你可以试别的ҎQ如果有更好的话Q请告诉我?br />q里我搜索:x64、asm{关键字Q修改d:\TrueCrypt\Crypto\Makefile.inc文gZ面这样即可:
      ?    !if "$(TC_ARCH)" == "x86"
      ?    TC_OBJ_FORMAT = win32
      ?    !else
      ?    #TC_OBJ_FORMAT = win64
      ?    #edit by gocool, if the x64 system need the nasm.exe use the x64 format parameters for executing.
      ?    #abort the x64 system here for building.
      ?    #2009/12/23
      ?    TC_OBJ_FORMAT = win32
      ?    TC_ARCH = x86
      ?0    !endif
      ?1   
      ?2    "$(OBJ_PATH)\$(O)\Aes_$(TC_ARCH).obj": Aes_$(TC_ARCH).asm
      ?3        nasm.exe -Xvc -f $(TC_OBJ_FORMAT) -Ox -D DLL_EXPORT -o "$@" -l "$(OBJ_PATH)\$(O)\Aes_$(TC_ARCH).lst" Aes_$(TC_ARCH).asm
      其中Qؓ了减变化量Q也利于以后恢复Q第4-7行ؓ注释Q第8?行我非x86的情况也定义成x86的情况,q样无论如何下面W?3行的语句都将执行以x86体系为结构的讄Q而这L讄通常是正的?br />
    2. fatal error LNK1000: Internal error during IncrBuildImage
      据说是Microsoft Visual Studio 2008的一个BUG。http://blog.csdn.net/just_one_two/archive/2009/10/05/4634391.aspx
      听说有两U方法,一U是Ҏ1Q需要下载补丁,我没有尝试。第二种通过修改配置的方法我成功了,步骤如下Q?br />ҎQ项?>属?>链接?>常规   下面?#8220;启用增量链接”Q将“?/INCREMENTAL)”改ؓ“?/INCREMENTAL:NO)”?br />不过q又引入了另外一个警告:3>FormatCom.obj : warning LNK4075: 忽略“/EDITANDCONTINUE”(׃“/INCREMENTAL:NO”规范)
      选择目,属?>配置属?>C/C++Q修?#8220;调试信息格式”?#8220;E序数据?/Zi)”卛_?br />
    3. 警告Q未扑ֈ下列环境变量
      4>目 : warning PRJ0018 : 未找C列环境变?
      4>$(PKCS11_INC)
      ׃目属性里讄有附加包含目?#8220;$(PKCS11_INC)”Q因此编译的时候会在系l变量里LPKCS11_INC目Q如果找不到Q则l出警告Q因此,我们需要手动补充这个项。方法同步骤5Q增加一个变量ؓPKCS11_INCQ|D:\TrueCrypt\CommonQ其中,值就是之前我们拷贝三个文Ӟpkcs11.h、pkcs11f.h、pkcs11t.hQ的目录?br />
    4. 如果不出意外的话Q你可能q会得到一个用了PKEY_AppUserModel_ID未定义的声明W的错误。这个是用于标识用户态应用程序的唯一标识。你可以在Setup.h文g中定义:
      /*---region add by gc---*/
      #include "wtypes.h"
          const PROPERTYKEY PKEY_AppUserModel_ID = {
              {
                  (unsigned long)2009,/*unsigned long  Data1;*/
                  (unsigned short)12,/*unsigned short Data2;*/
                  (unsigned short)23,/*unsigned short Data3;*/
                  0x44,0x55,0x55,0x55,0x55,0x55,0x55,0x55
              },/*GUID fmtid;*/
              (DWORD)PID_FIRST_USABLE /*DWORD pid;*/
          };
      /*---endregion---*/
      其中Q这个结构体是由GUID和PID共同l成的?br />

下蝲链接

  • TrueCrypt下蝲Qhttp://www.sfr-fresh.com/windows/misc/TrueCrypt-6.2a-Source.zip:a/Boot/Windows/Makefile
  • WinDDK下蝲Qhttp://www.microsoft.com/whdc/DevTools/WDK/WDKpkg.mspx
  • PKCS11下蝲Qhttp://svn.openvpn.net/projects/openvpn/test/time/openvpn/pkcs11-headers/
  • GZip下蝲Qhttp://www.gzip.org/ 或?http://www.gzip.org/gz124src.zip
  • Nasm下蝲Qhttp://www.nasm.us/pub/nasm/releasebuilds/2.07/win32/
  • MSVC1.52下蝲Qhttp://download.csdn.net/source/620960 Q?5.02MBQ(g|上很多人都在找1.52Q最后一个可以编?6bitE序的VC~译器)Q但官方|站上没有公开下蝲的链接,实在非常郁闷Q我从MSDN订阅下蝲Q收费的噢,杯具Q则?7.6MBQ,如果大家实在找不C载或?5.02MB的不可用Q可以联pL?/li>

    参考链?/h3>
    • http://blog.csdn.net/skyremember/archive/2009/09/17/4562090.aspx
    • http://blog.sina.com.cn/s/blog_4758691d0100d8mc.html
    • http://lll332.blog.163.com/blog/static/1553692220093404635752/
    • http://msdn.microsoft.com/en-us/library/aa373931%28VS.85%29.aspx
    • http://hi.baidu.com/hhacker/blog/item/2fc5b3fb0b24132a4f4aea1d.html
    • http://blog.csdn.net/just_one_two/archive/2009/10/05/4634391.aspx
    • http://blog.csdn.net/liufei_learning/archive/2009/12/21/5047632.aspx
    • http://msdn.microsoft.com/zh-cn/library/958x11bc%28VS.80%29.aspx
    • http://bbs.xiakexing.com/cgi-bin/topic.cgi?forum=22&topic=498


    volnet 2009-12-23 23:47 发表评论
    ]]>QuickSort快速排序法(2009-10-28)http://www.shnenglu.com/mymsdn/archive/2009/10/28/quicksort20091028.htmlvolnetvolnetTue, 27 Oct 2009 16:38:00 GMThttp://www.shnenglu.com/mymsdn/archive/2009/10/28/quicksort20091028.htmlhttp://www.shnenglu.com/mymsdn/comments/99624.htmlhttp://www.shnenglu.com/mymsdn/archive/2009/10/28/quicksort20091028.html#Feedback0http://www.shnenglu.com/mymsdn/comments/commentRss/99624.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/99624.html在本博客Q之前有一个版本的QuickSortQ其实网友很早就提出了相关的BUGQ但是我一直没有时间进行修正,今天又有朋友提出了这个BUGQ我刚好抽空看了一下,看来自己是相当不严}以至于犯下了如此大错?/p>

    原文链接Q?a href="http://www.shnenglu.com/mymsdn/archive/2009/03/06/quicksort.aspx">http://www.shnenglu.com/mymsdn/archive/2009/03/06/quicksort.aspx Q未修复Q?/p>

    关于修复BUG后的代码Q将在本文中提供Q原文中不进行修改,但会有提C指明是错误的,有兴的朋友也可以直接在原文的代码中L错误来锻D己排错的能力?/p>

    下面是几段代码Q?/p>

    Algorithms.cpp

    #include "StdAfx.h"
    #include "Algorithms.h"
    Algorithms::Algorithms(void)
    {
    }
    
    Algorithms::~Algorithms(void)
    {
    }
    

    Algorithms.h

    #pragma once
    
    #include <iostream>
    
    class Algorithms
    {
    public:
        Algorithms(void);
        ~Algorithms(void);
    
    public:
        template <typename T>
        static void QuickSort(T* arr, size_t min, size_t max);
    private:
        template <typename T>
        static size_t qsort_helper_partition(T* arr, size_t min, size_t max);
        template <typename T>
        static inline void swap(T* arr, size_t x, size_t y);
        // helper
        template <typename T>
        static inline void helper_show_all(T* arr, size_t min, size_t max, char *msg);
    };
    
    template <typename T>
    void Algorithms::QuickSort(T* arr, size_t min, size_t max)
    {
        if(min >= max || max == 0 - 1) return;
        helper_show_all(arr, min, max, "before qsort_helper_partition");
        size_t p = qsort_helper_partition(arr, min, max);
        helper_show_all(arr, min, max, "after qsort_helper_partition");
    
        QuickSort(arr, min, p - 1);
        QuickSort(arr, p + 1, max);
    }
    /*
    *    @BUG:    bug200910280001
    *    @DESC:    ׃在@环while(true)中,假设原代?
                01    while(true)
                02    {
                03        while(cmp < arr[i])
                04            ++i;
                05        while(arr[j] < cmp)
                06            --j;
                07        if(i >= j) break;
                08
                09        swap(arr, i, j);
                10    }
                中,前两D(行号Q行P中的代码均返回falseQ?
                则无法进?+i或?-jQ那么在q个while(true)中,
                i和j的值将无法发生变化Q从而导致死循环?
        @LINK:http://www.shnenglu.com/mymsdn/archive/2009/03/06/quicksort.aspx#99606
    */
    template <typename T>
    size_t Algorithms::qsort_helper_partition(T* arr, size_t min, size_t max)
    {
        T cmp = arr[min];
        int i = min, j = max; // bug200910280001:修正i = min+1Q将+1的动作放在@环内?
        while(true)
        {
            while(cmp < arr[++i]) // bug200910280001:原本在循环外的min+1Q移q@环内Qƈ首先+1
                ; // bug200910280001:?+1U至while条g中?
            while(arr[j] < cmp)
                --j;
            if(i >= j) break;
    
            helper_show_all(arr, min, max, "before swap(arr, i, j)");
            swap(arr, i, j);
            helper_show_all(arr, min, max, "after swap(arr, i, j)");
        }
        swap(arr, min, j);
        return j;
    }
    
    template <typename T>
    void Algorithms::swap(T* arr, size_t x, size_t y)
    {
        T tmp = arr[x];
        arr[x] = arr[y];
        arr[y] = tmp;
    }
    
    template <typename T>
    void Algorithms::helper_show_all(T* arr, size_t min, size_t max, char *msg)
    {
        std::cout << "current array :\t";
        for(int i = min; i < max; ++i)
        {
            std::cout << arr[i] << " ";
        }
        std::cout<<"\t//"<<msg;
        std::cout<<std::endl;
    }

    cpp_quickSort.cpp

    // cpp_quickSort.cpp : 定义控制台应用程序的入口炏V?
    //
    
    #include "stdafx.h"
    #include "Algorithms.h"
    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        int arr_begin = 0;
        int arr_length = 12; //The length will instead of the magic numbers 
        int arr[] = {8, 3, 7, 1, 5, 6, 2, 1, 9, 9, 1, 1};
        
        // Test for : 20091028bug0001
        // int arr[] = {1, 1, 1};
    
        std::cout << "input array :\t";
        for(size_t i = arr_begin; i != arr_length; ++i)
        {
            std::cout<<arr[i]<<" ";
        }
        std::cout<<std::endl;
    
        Algorithms::QuickSort(arr, arr_begin, arr_length);
    
        std::cout << "result array :\t";
        for(size_t i = arr_begin; i != arr_length; ++i)
        {
            std::cout<<arr[i]<<" ";
        }
        std::cout<<std::endl;
    
        std::cout << "--------------------" << std::endl;
        std::cout << "input array :\t";
    
        std::vector<int> vec;
        vec.push_back(3);
        vec.push_back(1);
        vec.push_back(4);
        vec.push_back(1);
        vec.push_back(7);
        vec.push_back(6);
    
        for(std::vector<int>::iterator iter = vec.begin();
            iter != vec.end(); ++ iter)
        {
            std::cout<<*iter<<" ";
        }
        std::cout<<std::endl;
    
        std::sort(vec.begin(), vec.end());
    
        for(std::vector<int>::iterator iter = vec.begin();
            iter != vec.end(); ++ iter)
        {
            std::cout<<*iter<<" ";
        }
        std::cout<<std::endl;
    
        return 0;
    }
    
    


    volnet 2009-10-28 00:38 发表评论
    ]]>
    关于NULL在C和C++中的区别http://www.shnenglu.com/mymsdn/archive/2009/05/31/about-the-NULL-in-C-or-CPlusPlus.htmlvolnetvolnetSun, 31 May 2009 12:50:00 GMThttp://www.shnenglu.com/mymsdn/archive/2009/05/31/about-the-NULL-in-C-or-CPlusPlus.htmlhttp://www.shnenglu.com/mymsdn/comments/86308.htmlhttp://www.shnenglu.com/mymsdn/archive/2009/05/31/about-the-NULL-in-C-or-CPlusPlus.html#Feedback0http://www.shnenglu.com/mymsdn/comments/commentRss/86308.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/86308.html先看看标题所提到的内容:
    Ҏhttps://research.microsoft.com/en-us/um/redmond/projects/invisible/include/__defs.h.htm文档中的定义Q?br>
    #if !defined(NULL) && defined(__NEEDS_NULL)
    #ifdef __cplusplus
    #define NULL    0
    #else
    #define NULL    ((void *)0)
    #endif
    #endif
    在C和C++中,分别是由(void*)0?来表C的?br>?\0'是ASCII中的|ASCII中它的值就??br>所以它们三者是相同的?br>
    参考资料:
    https://research.microsoft.com/en-us/um/redmond/projects/invisible/include/__defs.h.htm

    在探I的q程中找C面的一个帖子。很是不错,COPY如下?br>转蝲自:http://blog.chinaunix.net/u/18517/showart_309917.html


        本文转自Q?a >http://bbs.chinaunix.net/viewthread.php?tid=544415&extra=&page=7
        帖子里讨ZC语言中的I指针、空指针帔R、NULL?{概念及怺关系及区别。这里摘录whyglinux兄的ȝ。做个标{,呵呵^_^

    1. 什么是I指针常量(null pointer constantQ?

      [6.3.2.3-3] An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.

      q里告诉我们Q??L?\0'? - 3? * 17 Q它们都?#8220;integer constant expression”Q以?(void*)0 Q?font color="#990033">tycQ? 我觉?void*)0应该是一个空指针吧,更恰当一?/font>Q等都是I指针常量(注意 (char*) 0 不叫I指针常量,只是一个空指针|?font color="#0000ff">至于pȝ选取哪种形式作ؓI指针常量用,则是实现相关?/font>。一般的 C pȝ选择 (void*)0 或?0 的居多(也有个别的选择 0LQ;至于 C++ pȝQ由于存在严格的cd转化的要求,void* 不能?C 中那栯p{换ؓ其它指针cdQ所以通常?0 作ؓI指针常量(tyc: C++标准推荐Q,而不选择 (void*)0?br>
    2. 什么是I指针(null pointerQ?

      [6.3.2.3-3] If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

      因此Q如?p 是一个指针变量,?p = 0;、p = 0L;、p = '\0';、p = 3 - 3;、p = 0 * 17; 中的M一U赋值操作之后(对于 C 来说q可以是 p = (void*)0;Q, p 都成Z个空指针Q?font color="#0000ff">ql保证空指针不指向Q何实际的对象或者函?/font>。反q来_M对象或者函数的地址都不可能是空指针。(tyc: 比如q里?void*)0是一个空指针。把它理解ؓnull pointerq是null pointer constant会有微秒的不同,当然也不是紧要了Q?br>
    3. 什么是 NULLQ?br>
      [6.3.2.3-Footnote] The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant

      ?NULL 是一个标准规定的宏定义,用来表示I指针常?/font>。因此,除了上面的各U赋值方式之外,q可以用 p = NULL; 来 p 成ؓ一个空指针。(tycQ很多系l中的实玎ͼ#define NULL (void*)0Q与q里?#8220;a null pointer constant”q不是完全一致的Q?br>
    4. I指针(null pointerQ指向了内存的什么地方(I指针的内部实现Q?

      标准q没有对I指针指向内存中的什么地方这一个问题作定,也就是说用哪个具体的地址|0x0 地址q是某一特定地址Q表C空指针取决于系l的实现。我们常见的I指针一般指?0 地址Q即I指针的内部用全 0 来表C(zero null pointerQ零I指针)Q也有一些系l用一些特D的地址值或者特D的方式表示I指针(nonzero null pointerQ非零空指针Q,具体请参?a target="_blank">C FAQ?br>
      q运的是Q在实际~程中不需要了解在我们的系l上I指针到底是一?zero null pointer q是 nonzero null pointerQ?font color="#0000ff">我们只需要了解一个指针是否是I指针就可以了——编译器会自动实现其中的转换Qؓ我们屏蔽其中的实现细节?/font>注意Q不要把I指针的内部表示{同于整? 0 的对象表C——如上所qͼ有时它们是不同的?br>
    5. 如何判断一个指针是否是一个空指针Q?/font>

      q可以通过与空指针帔R或者其它的I指针的比较来实玎ͼ注意与空指针的内部表C无养I。例如,假设 p 是一个指针变量,q 是一个同cd的空指针Q要?p 是否是一个空指针Q可以采用下列Q意Ş式之一——它们在实现的功能上都是{h的,所不同的只是风格的差别?br>
      指针变量 p 是空指针的判断:
      if ( p == 0 )
      if ( p == '\0' )
      if ( p == 3 - 3 )
      if ( p == NULL )  /* 使用 NULL 必须包含相应的标准库的头文g */
      if ( NULL == p )
      if ( !p )
      if ( p == q )
      ...

      指针变量 p 不是I指针的判断Q?br>if ( p != 0 )
      if ( p != '\0' )
      if ( p != 3 - 3 )
      if ( p != NULL )  /* 使用 NULL 必须包含相应的标准库的头文g */
      if ( NULL != p )
      if ( p )
      if ( p != q )
      ...

    6. 可以?memset 函数来得C个空指针吗?

      q个问题{同于:如果 p 是一个指针变量,那么

      memset( &p, 0, sizeof(p) ); ?p = 0;

      是等L吗?

      {案是否定的Q虽然在大多数系l上是等LQ但是因为有的系l存在着“非零I指?#8221; Qnonzero null pointerQ,所以这时两者不{h。由于这个原因,要注意当惛_指针讄为空指针的时候不应该使用 memsetQ而应该用I指针常量或I指针对指针变量赋值或者初始化的方法?br>
    7. 可以定义自己?NULL 的实现吗Q兼{?NULL 的值可以是 1?? {值吗Q?cM问题

      [7.1.3-2] If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined.

      NULL 是标准库中的一个符合上q条件的 reserved identifier Q保留标识符Q。所以,如果包含了相应的标准头文件而引入了 NULL 的话Q则再在E序中重新定?NULL Z同的内容是非法的Q其行ؓ是未定义的。也是_如果是符合标准的E序Q其 NULL 的值只能是 0Q不可能是除 0 之外的其它|比如 1?? {?br>
    8. malloc 函数在分配内存失败时q回 0 q是 NULLQ?br>
      malloc 函数是标?C 规定的库函数。在标准中明规定了在其内存分配p|时返回的是一?“null pointer”Q空指针Q:

      [7.20.3-1] If the space cannot be allocated, a null pointer is returned.

      对于I指针|一般的文档Q比? manQ中們֐于用 NULL 表示Q而没有直接说?0。但是我们应该清楚:对于指针cd来说Q返?NULL ?q回 0 是完全等LQ因?NULL ?0 都表C?“null pointer”Q空指针Q。(tycQ一般系l中手册中都q回NULLQ那我们qNULL?/font>Q?/li>

    另外Q附C FAQ上关于null pointer的解释:C FAQQnull pointer




    volnet 2009-05-31 20:50 发表评论
    ]]>
    如何查看你可以分配多大内?/title><link>http://www.shnenglu.com/mymsdn/archive/2009/05/25/85667.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Sun, 24 May 2009 17:37:00 GMT</pubDate><guid>http://www.shnenglu.com/mymsdn/archive/2009/05/25/85667.html</guid><wfw:comment>http://www.shnenglu.com/mymsdn/comments/85667.html</wfw:comment><comments>http://www.shnenglu.com/mymsdn/archive/2009/05/25/85667.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/mymsdn/comments/commentRss/85667.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/mymsdn/services/trackbacks/85667.html</trackback:ping><description><![CDATA[<pre class="gc-code"><span style="color: #7f0055">#include </span><span style="color: #2a00ff"><stdio.h> </span><span style="color: #7f0055">#include </span><span style="color: #2a00ff"><stdlib.h> </span><span style="color: #7f0055">int </span>main(<span style="color: #7f0055">void</span>){ <span style="color: #7f0055">int </span>MB = 0; <span style="color: #7f0055">while</span>(<span style="color: #642880">malloc</span>(1 << 20)) ++MB; <span style="color: #642880">printf</span>(<span style="color: #2a00ff">"Allocated %d MB total\n"</span>, MB); <span style="color: #7f0055">return </span>EXIT_SUCCESS; }</pre> <p>原理Q因??0ơ方是1MBQ??0ơ方?KBQ??0ơ方?GBQ以此类推)?/p> <p>如果你请求分配的内存块小?MBQ你得到的内存是否比q要多一些呢Qؓ什么?</p> <p>{:</p> <p>q不是绝对的Q?/p> <p>在本例中使用</p> <p>1<<22Q?MBQ得到的l果??000MB</p> <p>1<<21Q?MBQ得到的l果??972MB</p> <p>1<<20Q?MBQ得到的l果?918MB</p> <p>1<<19Q?.5MBQ得到的l果??812MB</p> <p>1<<18Q?.25MBQ得到的l果??003MB</p> <p>1<<17Q?.125MBQ得到的l果??034MB</p> <p>昄出现了一个意外的l果?/p><img src ="http://www.shnenglu.com/mymsdn/aggbug/85667.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/mymsdn/" target="_blank">volnet</a> 2009-05-25 01:37 <a href="http://www.shnenglu.com/mymsdn/archive/2009/05/25/85667.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>static in Chttp://www.shnenglu.com/mymsdn/archive/2009/05/24/85626.htmlvolnetvolnetSun, 24 May 2009 10:17:00 GMThttp://www.shnenglu.com/mymsdn/archive/2009/05/24/85626.htmlhttp://www.shnenglu.com/mymsdn/comments/85626.htmlhttp://www.shnenglu.com/mymsdn/archive/2009/05/24/85626.html#Feedback3http://www.shnenglu.com/mymsdn/comments/commentRss/85626.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/85626.html

    #include <stdio.h>
    #include <stdlib.h>
    
    char * favorite_fruit1(void);
    char * favorite_fruit2(void);
    void favorite_fruit3(char **);
    int main(void) {
        char * fruit1 = favorite_fruit1();
        printf("%s\n", fruit1);
    
        char * fruit2 = favorite_fruit2();
        printf("%s\n", fruit2);
    
        char * fruit3 = NULL;
        favorite_fruit3(&fruit3);
        printf("%s\n", fruit3);
    
        printf("------END of CODE------");
        return EXIT_SUCCESS;
    }
    char * favorite_fruit1(void){
        char deciduous[] = "apple";
        return deciduous;
    }
    char * favorite_fruit2(void){
        static char deciduous[] = "apple";
        return deciduous;
    }
    void favorite_fruit3(char ** fruit){
        static char deciduous[] = "apple";
        *fruit = deciduous;
    }

    favorite_fruit1很明显会出现问题Q原因是因ؓchar deciduous[]是局部变量,在函数调用返回后Q就释放了?/p>

    favorite_fruit2因ؓ使用了staticQ而static限定了变量被保存在数据段Qdata segmentQ中Q它的声明周期同E序一样长。所以不会出错?/p>

    favorite_fruit3是另一U有效的写法Q其原理??/p>

    volnet 2009-05-24 18:17 发表评论
    ]]>
    [C专家~程]学习W记——a.outQ段(segment)Q查看可执行文g中的D?/title><link>http://www.shnenglu.com/mymsdn/archive/2009/05/19/expert-c-programming-a-out-segment.html</link><dc:creator>volnet</dc:creator><author>volnet</author><pubDate>Tue, 19 May 2009 15:50:00 GMT</pubDate><guid>http://www.shnenglu.com/mymsdn/archive/2009/05/19/expert-c-programming-a-out-segment.html</guid><wfw:comment>http://www.shnenglu.com/mymsdn/comments/83424.html</wfw:comment><comments>http://www.shnenglu.com/mymsdn/archive/2009/05/19/expert-c-programming-a-out-segment.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/mymsdn/comments/commentRss/83424.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/mymsdn/services/trackbacks/83424.html</trackback:ping><description><![CDATA[本部分内容详见《C专家~程》P119<br>查看可执行文件中的段<br>1.~译“hello world”E序Q在可执行文件中执行ls -lQ得到文件的M大小。运行size得到文g里各个段的大?br>2.增加一个全局的int[1000]数组声明Q重新进行编译,再用上面的命令得到M及各个段的大,注意前后的区别?br>3.现在Q在数组的声明中增加初始|CQC语言q不Ҏl进行初始化时ؓ每个元素提供初始|。这数组从BSSD{换到数据Dc重复上面的量Q注意各个段前后大小的区别?br>4.现在Q在函数内声明一个巨大的数组。然后再声明一个巨大的局部数l,但这ơ加上初始倹{重复上面的量。定义于函数内部的局部数l存储在可执行文件中吗?有没有初始化有什么不同吗Q?br>5.如果在调试状态下~译Q文件和D늚大小有没有变化?是ؓ了最大程度的优化吗?<br>分析上面“~程挑战”的结果,使自q信:<br> <ul> <li>数据D保存在目标文g中?/li> <li>BSSD不保存在目标文件中Q除了记录BSSD在q行时所需要的大小Q?/li> <li>文本D|最Ҏ受优化措施媄响的Dc?/li> <li>a.out文g的大受调试状态下~译的媄响,但段不受影响?/li> </ul> helloworld.c的文件最l如下:<br> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">#include </span><span style="color: #000000;"><</span><span style="color: #000000;">stdio.h</span><span style="color: #000000;">></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;"> global_array[</span><span style="color: #000000;">1000</span><span style="color: #000000;">] </span><span style="color: #000000;">=</span><span style="color: #000000;"> {</span><span style="color: #000000;">100</span><span style="color: #000000;">, </span><span style="color: #000000;">101</span><span style="color: #000000;">, </span><span style="color: #000000;">102</span><span style="color: #000000;">};<br></span><span style="color: #0000ff;">void</span><span style="color: #000000;"> SayGoodBye(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">);<br></span><span style="color: #0000ff;">int</span><span style="color: #000000;"> main(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">)<br>{<br>        printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">hello Linux world</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>        </span><span style="color: #0000ff;">int</span><span style="color: #000000;"> main_array[</span><span style="color: #000000;">1000</span><span style="color: #000000;">] </span><span style="color: #000000;">=</span><span style="color: #000000;"> {</span><span style="color: #000000;">10</span><span style="color: #000000;">, </span><span style="color: #000000;">20</span><span style="color: #000000;">, </span><span style="color: #000000;">30</span><span style="color: #000000;">, </span><span style="color: #000000;">40</span><span style="color: #000000;">};<br>        SayGoodBye();<br>        </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> </span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}<br><br></span><span style="color: #0000ff;">void</span><span style="color: #000000;"> SayGoodBye(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">)<br>{<br>        </span><span style="color: #0000ff;">int</span><span style="color: #000000;"> goodbye_array[</span><span style="color: #000000;">1000</span><span style="color: #000000;">] </span><span style="color: #000000;">=</span><span style="color: #000000;"> {</span><span style="color: #000000;">1024</span><span style="color: #000000;">, </span><span style="color: #000000;">2048</span><span style="color: #000000;">, </span><span style="color: #000000;">4096</span><span style="color: #000000;">};<br>        printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">good bye user!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>}<br></span></div> <br>以下命o按照文中步骤依次修改上文代码Q过E不赘述Q,q行size后的数据如下所C:<br> <div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">[volnet@GoCool c]$ echo </span><span style="color: #000000;">"</span><span style="color: #000000;">size helloworld1</span><span style="color: #000000;">"</span><span style="color: #000000;">; size helloworld1; echo </span><span style="color: #000000;">"</span><span style="color: #000000;">size helloworld2</span><span style="color: #000000;">"</span><span style="color: #000000;">; size helloworld2; echo </span><span style="color: #000000;">"</span><span style="color: #000000;">size helloworld3</span><span style="color: #000000;">"</span><span style="color: #000000;">; size helloworld3; echo </span><span style="color: #000000;">"</span><span style="color: #000000;">size helloworld4</span><span style="color: #000000;">"</span><span style="color: #000000;">; size helloworld4;<br>size helloworld1<br>   text       data        bss        dec        hex    filename<br>   </span><span style="color: #000000;">1015</span><span style="color: #000000;">        </span><span style="color: #000000;">252</span><span style="color: #000000;">          </span><span style="color: #000000;">8</span><span style="color: #000000;">       </span><span style="color: #000000;">1275</span><span style="color: #000000;">        4fb    helloworld1<br>size helloworld2<br>   text       data        bss        dec        hex    filename<br>   </span><span style="color: #000000;">1015</span><span style="color: #000000;">        </span><span style="color: #000000;">252</span><span style="color: #000000;">       </span><span style="color: #000000;">4032</span><span style="color: #000000;">       </span><span style="color: #000000;">5299</span><span style="color: #000000;">       14b3    helloworld2<br>size helloworld3<br>   text       data        bss        dec        hex    filename<br>   </span><span style="color: #000000;">1015</span><span style="color: #000000;">       </span><span style="color: #000000;">4280</span><span style="color: #000000;">          </span><span style="color: #000000;">8</span><span style="color: #000000;">       </span><span style="color: #000000;">5303</span><span style="color: #000000;">       14b7    helloworld3<br>size helloworld4<br>   text       data        bss        dec        hex    filename<br>   </span><span style="color: #000000;">1270</span><span style="color: #000000;">       </span><span style="color: #000000;">4280</span><span style="color: #000000;">          </span><span style="color: #000000;">8</span><span style="color: #000000;">       </span><span style="color: #000000;">5558</span><span style="color: #000000;">       15b6    helloworld4<br></span></div> <br>注:<br>BSS的全U是QBlock Started by SymbolQ由W号开始的块)Q它是旧式IBM704汇编E序的一个伪指oQUNIX借用了这个名字,至今依然沿用?br> <img src ="http://www.shnenglu.com/mymsdn/aggbug/83424.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/mymsdn/" target="_blank">volnet</a> 2009-05-19 23:50 <a href="http://www.shnenglu.com/mymsdn/archive/2009/05/19/expert-c-programming-a-out-segment.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Expert C Programming noteshttp://www.shnenglu.com/mymsdn/archive/2009/04/01/78518.htmlvolnetvolnetTue, 31 Mar 2009 16:31:00 GMThttp://www.shnenglu.com/mymsdn/archive/2009/04/01/78518.htmlhttp://www.shnenglu.com/mymsdn/comments/78518.htmlhttp://www.shnenglu.com/mymsdn/archive/2009/04/01/78518.html#Feedback0http://www.shnenglu.com/mymsdn/comments/commentRss/78518.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/78518.html1、const其实q不是真正的帔RQP32Q?/p>

    const_is_not_constant

    2、早期的gets()中的BugD了Internet蠕虫QP42Q?/p>

    gets()函数q不查缓冲区的空_事实上它也无法检查缓冲区的空间。如果函数的调用者提供了一个指向堆栈的指针Qƈ且gets()函数d的字W数量超q缓冲区的空_gets()函数会愉快地将多出来的字符l箋写入到堆栈中Q这p盖了堆栈原先的内宏V——这是病毒利用它来写入额外I间Qƈ引发蠕虫病毒的前提?/p>

    推荐的方式是?/p>

    gets(line)

    替换?/p>

    if(fgets(line, sizeof(line), stdin) == NULL)

    exit(1);

    3、相dW串帔R自动q接QP45Q?/p>

    q个其实已经应用很普遍了Q但是我个h用的比较,Ҏ记录一下?/p>

    ansi-c_connect_string

    4、返回一个指针?QP48Q?/p>

    q个话题围绕一个程序的BUG来展开Q这个程序返回了局部变量的值的指针Q这么说当然你一眼就能看得出来问题所在,但是在很多时候,q个错误却L在你的眼皮子底下溜走?/p>

    作者提供了五种方式Q只能说可以用,但唯一推荐的只有一个,详见作者的分析QP48Q(不是什么高q理论Q你自己也能分析地出来)?/p>

    a.q回一个字W串帔R的指针。因为常量存在静态数据存储区Q所以指针没问题?/p>

    b.使用全局声明的数l。提到全局两个字,q道这个方法有很大的局限性?/p>

    c.使用静态数l。下一ơ调用将覆盖q个数组内容?/p>

    char * func() {

    static char buffer[20];

    ?/p>

    return buffer;

    }

    d.昑ּ分配一些内存,保存q回的倹{?/p>

    char  * func() {

    char * s = malloc(120);

    ?/p>

    return s;

    }

    既然用到了mallocQ就必然伴随着freeQ因此带来了内存理的问题,增加了开发者负担?/p>

    e.Q?u>推荐Q在调用前后Q由函数调用者分配内存,q由光放,在同一地方释放对于内存理来说代h相对最?/p>

    void func( char * result, int size) {

    ?/p>

    strncpy(result, “That’d be in the data segment, Bob? size);

    }

    buffer = malloc(size);

    func(buffer, size);

    ?/p>

    free(buffer);



    volnet 2009-04-01 00:31 发表评论
    ]]>
    QuickSort快速排序法(2009-03-06)http://www.shnenglu.com/mymsdn/archive/2009/03/06/quicksort.htmlvolnetvolnetThu, 05 Mar 2009 19:03:00 GMThttp://www.shnenglu.com/mymsdn/archive/2009/03/06/quicksort.htmlhttp://www.shnenglu.com/mymsdn/comments/75693.htmlhttp://www.shnenglu.com/mymsdn/archive/2009/03/06/quicksort.html#Feedback5http://www.shnenglu.com/mymsdn/comments/commentRss/75693.htmlhttp://www.shnenglu.com/mymsdn/services/trackbacks/75693.html var totalConfirmTime = 10; var currentConfirmTime = 0; var enableNoticeReader = true; var enableCloseNotice = true; function onRedirect20091028(){ if(enableNoticeReader && currentConfirmTime < totalConfirmTime) { if(confirm("您已l在本页面逗留"+ 10*(++currentConfirmTime) +"U,本页面代码存在BUGQ\n是否认跌{到正代码页面《QuickSort快速排序法(2009-10-28)》?")) { window.location.href="http://www.shnenglu.com/mymsdn/archive/2009/10/28/quicksort20091028.html?source=20090306&method=setTimeOut" } else { if(enableCloseNotice) { if(confirm("我们最多提C您"+ totalConfirmTime +"ơ。\n如果您决定l逗留在本,是否需要关闭页面提醒?\nQ点几Z是”即可关闭!Q?)) { enableNoticeReader = false; } else { setTimeout(onRedirect20091028, 10000); } // only 1 time. enableCloseNotice = false; } else { setTimeout(onRedirect20091028, 10000); } } } } function closeEnableNoticeReader(){ enableNoticeReader = false; } setTimeout(onRedirect20091028, 10000);

    本文代码已经更新Q修正严重BUGQ最新版本详见?a href="http://www.shnenglu.com/mymsdn/archive/2009/10/28/quicksort20091028.html">QuickSort快速排序法(2009-10-28)》!

    本文中所涉及的代码未做更斎ͼL步最新版查阅正确代码Q?/p>

    链接Q?a title="http://www.shnenglu.com/mymsdn/archive/2009/10/28/quicksort20091028.html" href="http://www.shnenglu.com/mymsdn/archive/2009/10/28/quicksort20091028.html">http://www.shnenglu.com/mymsdn/archive/2009/10/28/quicksort20091028.html


    快速排序法Q(好土Q感觉满世界都会Q不q还是写一下,当然了,标准库里多的是排序算法)Q这里还是实现经典版的快速排序了Q时间复杂度O(nlogn)

    Algorithms.h

    #pragma once
    
    #include <iostream>
    
    class Algorithms
    {
    public:
        Algorithms(void);
        ~Algorithms(void);
    
    public:
        template <typename T>
        static void QuickSort(T* arr, size_t min, size_t max);
    private:
        template <typename T>
        static size_t qsort_helper_partition(T* arr, size_t min, size_t max);
        template <typename T>
        static inline void swap(T* arr, size_t x, size_t y);
    };
    
    template <typename T>
    void Algorithms::QuickSort(T* arr, size_t min, size_t max)
    {
        if(min >= max || max == 0 - 1) return;
        size_t p = qsort_helper_partition(arr, min, max);
    
        QuickSort(arr, min, p - 1);
        QuickSort(arr, p + 1, max);
    }
    
    template <typename T>
    size_t Algorithms::qsort_helper_partition(T* arr, size_t min, size_t max)
    {
        T cmp = arr[min];
        int i = min + 1, j = max;
        while(true)
        {
            while(cmp < arr[i])
                ++i;
            while(arr[j] < cmp)
                --j;
            if(i >= j) break;
    
            swap(arr, i, j);
        }
        swap(arr, min, j);
        return j;
    }
    
    template <typename T>
    void Algorithms::swap(T* arr, size_t x, size_t y)
    {
        T tmp = arr[x];
        arr[x] = arr[y];
        arr[y] = tmp;
    }

    用法Q(Z有标准库的排序法Q当然只是调一下,没有什么可说的了)

    #include "Algorithms.h"
    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        int arr[] = {4, 8, 3, 7, 1, 5, 6, 2};
    
        for(size_t i = 0; i != 8; ++i)
        {
            std::cout<<arr[i]<<" ";
        }
        std::cout<<std::endl;
    
        Algorithms::QuickSort(arr,0, 7);
    
        for(size_t i = 0; i != 8; ++i)
        {
            std::cout<<arr[i]<<" ";
        }
        std::cout<<std::endl;
    
        std::vector<int> vec;
        vec.push_back(3);
        vec.push_back(1);
        vec.push_back(4);
        vec.push_back(1);
        vec.push_back(7);
        vec.push_back(6);
    
        for(std::vector<int>::iterator iter = vec.begin();
            iter != vec.end(); ++ iter)
        {
            std::cout<<*iter<<" ";
        }
        std::cout<<std::endl;
    
        std::sort(vec.begin(), vec.end());
    
        for(std::vector<int>::iterator iter = vec.begin();
            iter != vec.end(); ++ iter)
        {
            std::cout<<*iter<<" ";
        }
        std::cout<<std::endl;
    
        return 0;
    }
    
    


    volnet 2009-03-06 03:03 发表评论
    ]]>
    þŮƷƷ| ޹˾þһþ| þֻǾƷ23| þҹɫ˾Ʒ| þҹɫ˾Ʒ| þþ| þ66͵Ʒ9| þþþѾƷ| ƷþþĻһ| þAVӰ| ձƷþþþĻ8| þ°Ҳȥ| þۺۺϾþ97ɫ| ۺϾþþƷɫ| ƷƷھþø| þۺϳ| þ޹ҹƷƬ| þоƷ| ƷþþþþĻ| AVݺɫۺϾþ| ŷƷ˿þþĻ| AVһȾþ| ҹƷþþþþ| ˾Ʒþ| 99Ʒþ| þþƷ޾Ʒ2020| 2020þþƷۺһ| 91Ʒþþþþ91| þþƷһ | þˬ˰| 999þþѹƷ| þþƷAV뽿ɫ| þþù99þùһ| 91þþƷӰ| þԭƷ | ɫþþþۺ | ձþĻ| Ʒþþþþ˳| ۺۺϾþ69| þһ| þù׾Ʒҹ|