??xml version="1.0" encoding="utf-8" standalone="yes"?>99久久99久久精品国产,7777久久久国产精品消防器材,久久久99精品一区二区http://www.shnenglu.com/lf426/category/6366.htmlGame Design Using C++ and SDLzh-cnSat, 26 Jun 2010 21:39:42 GMTSat, 26 Jun 2010 21:39:42 GMT60d解密C++宽字W:6、国际化{略Q完Q?/title><link>http://www.shnenglu.com/lf426/archive/2010/06/26/118788.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Sat, 26 Jun 2010 11:55:00 GMT</pubDate><guid>http://www.shnenglu.com/lf426/archive/2010/06/26/118788.html</guid><wfw:comment>http://www.shnenglu.com/lf426/comments/118788.html</wfw:comment><comments>http://www.shnenglu.com/lf426/archive/2010/06/26/118788.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lf426/comments/commentRss/118788.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lf426/services/trackbacks/118788.html</trackback:ping><description><![CDATA[<a title="<本文pdf文档下蝲>" href_cetemp="http://www.163pan.com/files/c0x000k09.html"><本文PDF文档下蝲></a><br><br>编码的伤<br><br>我们现在知道QC/C++的宽H{换是依赖pȝ的locale的,q且在运行时完成。考虑q样一U情况,我们在简体中文Windows下编译如下语句:<br>const char* s = "中文abc";<br>Ҏ(gu)我们之前的讨论,~译器将按照Windows Codepage936QGB2312Q对q个字符串进行编码。如果我们在E序中运行宽H{换函敎ͼs转换为宽字符串wsQ如果这个程序运行在体中文环境下是没问题的,执行从GB2312到UCS-2BE的{换;但是Q如果在其他语言环境下,比如是繁体中文BIG5Q程序将Ҏ(gu)pȝ的locale执行从BIG5到UCS-2BE的{换,q显然就出现了错误?br><br>补救<br><br>有没有补救这个问题的办法呢?一个解x案就是执行不依赖locale的宽H{换。实际上Q这已l不是宽H{换之间的问题了,而是~码之间转换的问题了。我们可以用GNU的libiconv实现L~码间的转换Q对于以上的具体情况Q指明是从GB2312到UCS-2BE׃会出错。(请参考本人前面的章节Q?a title=win32下的libiconv href="http://www.shnenglu.com/lf426/archive/2008/03/30/45738.html">win32下的libiconv</a>Q,但这昄是一个笨拙的{略Q我们在体中文Windows下必M用GB2312到UCS-2BE版本的宽H{换函敎ͼCBIG5环境下,必重新写从BIG5到UCS-2BE的宽H{换函数?br><br>Windows的策?br><br>Windows的策略是淘汰了窄字符Ԍq脆只用宽字W串。所有的编码全部加上特定宏Q比如TEXT()Q如果程序是所谓Unicode~译Q在~译时就译为UCS2-BE——Windows自称为Unicode~程Q其本质是用了UCS-2BE?6位宽字符丌Ӏ?br><br>Linux的策?br><br>Linux下根本就不存在这个问题!因ؓ各种语言的Linux都用UTF-8的编码,所以,无论pȝlocale如何变化Q窄到宽转换的规则一直是UTF-8到UTF32-BE ?br><br>跨^台策?br><br>因ؓ?6位的范围内,UTF32-BE的前16位ؓ0Q后16位与UCS2-BE是一L(fng)Q所以,即wchar_t的sizeof()不一P在一般情况下Q跨q_使用宽字W(Ԍ也应该是兼容的。但是依然存在潜在的问题Q就是那?字节的UTF32~码?br><br>gettext{略<br><br>以上都是ASCII及以外的~码编码在E序中的办法。GNU的gettext提供了另外一U选择Q在E序中只编码ASCIIQ多语言支持由gettext函数库在q行时加载。(对gettext的介l请参考本人前面的章节Q?a title=Win32下的GetText href="http://www.shnenglu.com/lf426/archive/2008/03/30/45723.html">Win32下的GetText</a>Q。gettext的多语言译文g不在E序中,而是单独的提出来攑֜特定的位|。gettext明确的知道这些翻译文件的~码Q所以可以准的告诉l系l翻译的正确信息Q而系l将q些信息以当前的pȝlocale~码成窄字符串反馈给E序。例如,在简体中文Windows中,gettext的po文g也可以以UTF-8储存Qgettextpo文g译成mo文gQ确保mo文g在Q何系l和语言环境下都能够正确译。在q行是传lwin32E序的窄串符合当前localeQ是GB2312。gettext让国际化的翻译更加的方便Q缺Ҏ(gu)目前我没扑ֈ支持宽字W串的版本(据说是有ugettext()支持宽字W串Q,所以要使用gettext只能使用H字W串。但是gettext可以转换到宽字符Ԍ而且不会出现宽窄转换的问题,因ؓgettext是运行时Ҏ(gu)locale译的。例如:<br>const char* s = gettext("Chinese a b c");<br>其中"Chinese a b c"在po中的译?中文abc"<br>使用依赖locale的运行时宽窄转换函数Q?br>const std::wstring wstr = s2ws(s);<br>q行时调用该po文g对应的mo文gQ在体中文环境下׃GB2312传给E序Q在J体中文中就以BIG5传给E序Q这样s2ws()总能够正常换编码?br><br>更多<br><br>在本文的最后,我想回到C++的stream问题上。用fstream转换如此的简单,sstream却不支持。改造一个支持codecvt的string stream需要改造basic_stringbuf。basic_stringbuf和basic_filebuf都派生自basic_streambufQ所不同的是basic_filebuf在构造和open()的时候调用了codecvtQ只需要在basic_stringbuf中添加这个功能就可以了。说hҎ(gu)Q实际上是需要重新改造一个STL模板Q尽这些模板源代码都是在标准库头文件中现成的,但是我还是水qx限,没有LI了。另外一个思\是构Z个基于内存映的虚拟文gQ这个框架在boost的iostreams库中Q有兴趣的朋友可以深入的研究?br>Q完Q? <img src ="http://www.shnenglu.com/lf426/aggbug/118788.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lf426/" target="_blank">lf426</a> 2010-06-26 19:55 <a href="http://www.shnenglu.com/lf426/archive/2010/06/26/118788.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>d解密C++宽字W:5、利用fstream转换http://www.shnenglu.com/lf426/archive/2010/06/26/118779.htmllf426lf426Sat, 26 Jun 2010 08:40:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/26/118779.htmlhttp://www.shnenglu.com/lf426/comments/118779.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/26/118779.html#Feedback0http://www.shnenglu.com/lf426/comments/commentRss/118779.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/118779.html" href_cetemp="http://www.163pan.com/files/c0x000k09.html"><本文PDF文下蝲>

C++的流和本地化{略?br>
BS在设计C++的时候希望其具备化,q且是可扩展的智能化Q也是_C++的流可以“L”一些内宏V比如:
std::cout << 123 << "ok" << std::endl;
q句代码中,std::cout是能判断?23是int?ok"是const char[3]。利用流的智能,甚至可以做一些基cd的{换,比如从int到stringQstring到intQ?br>
std::string str("123");
std::stringstream sstr(str);
int i;
sstr 
>> i;
int i = 123;
std::stringstream sstr;
sstr 
<< i;
std::
string str = sstr.str();
管如此QC++q不满QC++甚至希望能“明白”旉Q货币的表示法。而时间和货币的表C方法在世界范围内是不同的,所以,每一个流都有自己的locale在媄响其行ؓQC++中叫做激z(imbueQ也有翻译成染Q。而我们知道,每一个locale都有多个facetQ这些facetqL被use_facet使用的。决定用哪些facet的,是流的缓存basic_streambuf及其zcbasic_stringbuf和basic_filebuf。我们要用到的facet是codecvtQ这个facet只被basic_filebuf使用——这是Z么只能用fstream来实现宽H{换,而无法用sstream来实现的原因?br>头文Ӟ
//filename string_wstring_fstream.hpp
#ifndef STRING_WSTRING_FSTREAM_HPP
#define STRING_WSTRING_FSTREAM_HPP

#include 
<string>

const std::wstring s2ws(const std::string& s);
const std::string ws2s(const std::wstring& s);

#endif
实现Q?br>
#include <string>
#include 
<fstream>
#include 
"string_wstring_fstream.hpp"

const std::wstring s2ws(const std::string& s)
{
    std::locale sys_loc(
"");

    std::ofstream ofs(
"cvt_buf");
    ofs 
<< s;
    ofs.close();

    std::wifstream wifs(
"cvt_buf");
    wifs.imbue(sys_loc);
    std::wstring wstr;
    wifs 
>> wstr;
    wifs.close();

    
return wstr;
}

const std::string ws2s(const std::wstring& s)
{
    std::locale sys_loc(
"");

    std::wofstream wofs(
"cvt_buf");
    wofs.imbue(sys_loc);
    wofs 
<< s;
    wofs.close();

    std::ifstream ifs(
"cvt_buf");
    std::
string str;
    ifs 
>> str;
    ifs.close();

    
return str;
}
在窄到宽的{化中Q我们先使用默认的本地化{略集(localeQ将s通过H文件流ofs传入文gQ这是char到char的传递,没有M转换Q然后我们打开宽文件流wifsQƈ用系l的本地化策略集QlocaleQ去Ȁz(imbueQ之Q流在读回宽串wstr的时候,是char到wchar_t的{换,q且因ؓȀzMsys_locQ所以实现标准窄到宽的{换?br>在宽到窄的{化中Q我们先打开的是宽文件流wofsQƈ且用pȝ的本地化{略集sys_locȀz(imbueQ之Q这时候,因ؓ要写的文件cvt_buf是一个外部编码,所以执行了从wchar_t到char的标准{换。读回来的文件流从char到charQ不做Q何{换?

lf426 2010-06-26 16:40 发表评论
]]>
d解密C++宽字W:4、利用codecvt和use_facet转换http://www.shnenglu.com/lf426/archive/2010/06/26/118772.htmllf426lf426Sat, 26 Jun 2010 05:39:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/26/118772.htmlhttp://www.shnenglu.com/lf426/comments/118772.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/26/118772.html#Feedback0http://www.shnenglu.com/lf426/comments/commentRss/118772.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/118772.html" href_cetemp="http://www.163pan.com/files/c0x000k09.html"><本文PDF文下蝲>

locale和facet

C++的locale框架比C更完备。C++除了一个笼l本地策略集localeQ还可以为locale指定具体的策略facetQ甚臛_以用自己定义的facetL造一个现有的locale产生一个新的locale。如果有一个facetcNewFacet需要添加到某个old_loc中Ş成新new_locQ需要另外一个构造函敎ͼ通常的做法是Q?br>std::locale new_loc(old_loc, new NewFacet);
标准库里的标准facet都具有自q有的功能Q访问一个locale对象中特定的facet需要用模板函数use_facetQ?br>template <class Facet> const Facet& use_factet(const locale&);
换一U说法,use_facet把一个facetcd例化成了对象Q由此就可以使用q个facet对象的成员函数?br>
codecvt

codecvt是一个标准facet。在C++的设计框枉Q这是一个通用的代码{换模李쀔—也是_q不是仅仅ؓ宽窄转换制定的?br>templat <class I, class E, class State> class std::codecvt: public locale, public codecvt_base{...};
I表示内部~码QE表示外部~码QState是不同{换方式的标识Q如果定义如下类型:
typedef std::codecvt<wchar_t, char, mbstate_t> CodecvtFacet;
那么CodecvtFacet是一个标准的宽窄转换facetQ其中mbstate_t是标准宽H{换的State?br>
内部~码和外部编?br>
我们考虑W?节中提到的C++~译器读取源文g时候的情ŞQ当dL"中文abc"的时候,外部~码Q也是源文件的~码Q是GB2312或者UTF-8的charQ而编译器必须其译为UCS-2BE或者UTF-32BE的wchar_tQ这也就是程序的内部~码。如果不是宽字符Ԍ内外~码都是charQ也׃需要{换了。类似的Q当C++d文g的时?Q就会可能需要到内外~码转换。事实上Qcodecvt正是被文g缓存basic_filebuf所使用的。理解这一点很重要Q原因会在下一节看到?br>
CodecvtFacet的in()和out()
因ؓ在CodecvtFacet中,内部~码讄为wchar_tQ外部编码设|ؓcharQ{换模式是标准宽窄转换mbstate_tQ所以,cL法in()是从char标准转换到wchar_tQout()是从wchar_t标准转换到char。这成了我们正需要的内外转换函数?br>result in(State& s, const E* from, const E* from_end, const E*& from_next, I* to,  I* to_end, I*& to_next) const;
result out(State& s, const I* from, const I* from_end, const I*& from_next, E* to, E* to_end, E*& to_next) const;
其中Qs是非const引用Q保存着转换位移状态信息。这里需要重点强调的是,因ؓ转换的实际工作交l了q行时库Q也是_转换可能不是在程序的主进E中完成的,而{换工作依赖于查询s的|因此Q如果s在{换结束前析构Q就可能抛出q行时异常。所以,最安全的办法是Q将s讄为全局变量Q?br>const?个指针分别是待{换字W串的v点,l点Q和出现错误时候的停点Q的下一个位|)Q另?个指针是转换目标字符串的L(fng)Q终点以及出现错误时候的停点Q的下一个位|)?br>
代码如下Q?br>头文?br>
//Filename string_wstring_cppcvt.hpp

#ifndef STRING_WSTRING_CPPCVT_HPP
#define STRING_WSTRING_CPPCVT_HPP

#include 
<iostream>
#include 
<string>

const std::wstring s2ws(const std::string& s);
const std::string ws2s(const std::wstring& s);

#endif
实现Q?br>
#include "string_wstring_cppcvt.hpp"

mbstate_t in_cvt_state;
mbstate_t out_cvt_state;

const std::wstring s2ws(const std::string& s)
{
    std::locale sys_loc(
"");

    
const char* src_str = s.c_str();
    
const size_t BUFFER_SIZE = s.size() + 1;

    wchar_t
* intern_buffer = new wchar_t[BUFFER_SIZE];
    wmemset(intern_buffer, 
0, BUFFER_SIZE);

    
const char* extern_from = src_str;
    
const char* extern_from_end = extern_from + s.size();
    
const char* extern_from_next = 0;
    wchar_t
* intern_to = intern_buffer;
    wchar_t
* intern_to_end = intern_to + BUFFER_SIZE;
    wchar_t
* intern_to_next = 0;

    typedef std::codecvt
<wchar_t, char, mbstate_t> CodecvtFacet;

    CodecvtFacet::result cvt_rst 
=
        std::use_facet
<CodecvtFacet>(sys_loc).in(
            in_cvt_state,
            extern_from, extern_from_end, extern_from_next,
            intern_to, intern_to_end, intern_to_next);
    
if (cvt_rst != CodecvtFacet::ok) {
        
switch(cvt_rst) {
            
case CodecvtFacet::partial:
                std::cerr 
<< "partial";
                
break;
            
case CodecvtFacet::error:
                std::cerr 
<< "error";
                
break;
            
case CodecvtFacet::noconv:
                std::cerr 
<< "noconv";
                
break;
            
default:
                std::cerr 
<< "unknown";
        }
        std::cerr    
<< ", please check in_cvt_state."
                    
<< std::endl;
    }
    std::wstring result 
= intern_buffer;

    delete []intern_buffer;

    
return result;
}

const std::string ws2s(const std::wstring& ws)
{
    std::locale sys_loc(
"");

    
const wchar_t* src_wstr = ws.c_str();
    
const size_t MAX_UNICODE_BYTES = 4;
    
const size_t BUFFER_SIZE =
                ws.size() 
* MAX_UNICODE_BYTES + 1;

    
char* extern_buffer = new char[BUFFER_SIZE];
    memset(extern_buffer, 
0, BUFFER_SIZE);

    
const wchar_t* intern_from = src_wstr;
    
const wchar_t* intern_from_end = intern_from + ws.size();
    
const wchar_t* intern_from_next = 0;
    
char* extern_to = extern_buffer;
    
char* extern_to_end = extern_to + BUFFER_SIZE;
    
char* extern_to_next = 0;

    typedef std::codecvt
<wchar_t, char, mbstate_t> CodecvtFacet;

    CodecvtFacet::result cvt_rst 
=
        std::use_facet
<CodecvtFacet>(sys_loc).out(
            out_cvt_state,
            intern_from, intern_from_end, intern_from_next,
            extern_to, extern_to_end, extern_to_next);
    
if (cvt_rst != CodecvtFacet::ok) {
        
switch(cvt_rst) {
            
case CodecvtFacet::partial:
                std::cerr 
<< "partial";
                
break;
            
case CodecvtFacet::error:
                std::cerr 
<< "error";
                
break;
            
case CodecvtFacet::noconv:
                std::cerr 
<< "noconv";
                
break;
            
default:
                std::cerr 
<< "unknown";
        }
        std::cerr    
<< ", please check out_cvt_state."
                    
<< std::endl;
    }
    std::
string result = extern_buffer;

    delete []extern_buffer;

    
return result;
}
最后补充说明一下std::use_facet<CodecvtFacet>(sys_loc).in()和std::use_facet<CodecvtFacet>(sys_loc).out()。sys_loc是系l的localeQ这个locale中就包含着特定的codecvt facetQ我们已ltypedefZCodecvtFacet。用use_facet对CodecvtFacetq行了实例化Q所以可以用这个facet的方法in()和out()?

lf426 2010-06-26 13:39 发表评论
]]>
d解密C++宽字W:3、利用Cq行时库函数转换http://www.shnenglu.com/lf426/archive/2010/06/26/118762.htmllf426lf426Sat, 26 Jun 2010 03:17:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/26/118762.htmlhttp://www.shnenglu.com/lf426/comments/118762.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/26/118762.html#Feedback1http://www.shnenglu.com/lf426/comments/commentRss/118762.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/118762.html" href_cetemp="http://www.163pan.com/files/c0x000k09.html"><本文PDF文下蝲>

std::locale

通过前面两节的知识,我们知道了在C/C++中,字符Q串Q和宽字W(Ԍ之间的{换不是简单的Q固定的数学关系Q宽H{换依赖于本地化策略集QlocaleQ。换句话_一个程序在q行之前q不知道pȝ的本地化{略集是什么,E序只有在运行之后才通过locale获得当时的本地化{略集?br>C有自qlocale函数Q我们这里直接介lC++的localecR?br>先讨论locale的构造函敎ͼ
locale() throw();
q个构造函数是获得当前E序的localeQ用法如下:
std::locale app_loc = std::locale();
或者(q是构造对象的两种表示方式Q后同)
std::locale app_loc;
另外一个构造函数是Q?br>explicit locale(const char* name);
q个构造函Cname的名字创建新的locale。重要的locale对象有:
std::locale sys_loc("");      //获得当前pȝ环境的locale
std::locale C_loc("C");      或?nbsp;     std::locale C_loc = std::locale::classic();      //获得C定义locale
std::locale old_loc = std::locale::global(new_loc);      //new_loc讄为当前全局localeQƈ原来的localeq回lold_loc
除了q些Q其它的name具体名字依赖于C++~译器和操作pȝQ比如Linux下gcc中文pȝ的locale名字?zh_CN.UTF-8"Q中文Windows可以?chs"Q更加完整的名字可以用name()函数查看Q?br>
mbstowcs()和wcstombs()

q两个Cq行时库函数依赖于全局localeq行转换Q所以,使用前必d讄全局locale?br>std::locale已经包含?lt;iostream>中了Q再加上我们需要用到的C++字符Ԍ所以包?lt;string>?br>我们先看H到宽的转换函数Q?br>
const std::wstring s2ws(const std::string& s)
{
    std::locale old_loc 
=
        std::locale::global(std::locale(
""));

    
const char* src_str = s.c_str();
    
const size_t buffer_size = s.size() + 1;
    wchar_t
* dst_wstr = new wchar_t[buffer_size];
    wmemset(dst_wstr, 
0, buffer_size);
    mbstowcs(dst_wstr, src_str, buffer_size);
    std::wstring result 
= dst_wstr;
    delete []dst_wstr;

    std::locale::global(old_loc);

    
return result;
}
我们全局locale讄为系llocaleQƈ保存原来的全局locale在old_loc中?br>在制定{换空间缓存大的时候,考虑如下Qchar是用1个或多个对象Q也是1个或者多个字节来表示各种W号Q比如,GB2312?个字节表C数字和字母Q?个字节表C汉字;UTF-8用一个字节表C数字和字母Q?个字节表C汉字,4个字节表CZ些很用到的W号Q比如音乐中G大调W号{。wchar_t是用1个对象(2字节或?字节Q来表示各种W号。因此,表示同样的字W串Q宽字符串的大小Q也是wchar_t对象的数量)L于或者等于窄字符串大(char对象数量Q的?1是ؓ了在最后预留一个gؓ0的对象,以便让C风格的char或者wchar_t字符串自动截断——这当然是宽串大等于窄串大的时候才会用上的Q大部分时候,字符串早在前面某个{换完毕的位置p0值对象所截断了?br>最后我们将全局locale讄回原来的old_loc?br>H串到宽串的转换函数Q?br>
const std::string ws2s(const std::wstring& ws)
{
    std::locale old_loc 
=
        std::locale::global(std::locale(
""));

    
const wchar_t* src_wstr = ws.c_str();
    size_t buffer_size 
= ws.size() * 4 + 1;
    
char* dst_str = new char[buffer_size];
    memset(dst_str, 
0, buffer_size);
    wcstombs(dst_str ,src_wstr, buffer_size);
    std::
string result = dst_str;
    delete []dst_str;

    std::locale::global(old_loc);

    
return result;
}
q里考虑转换I间~存大小的策略正好相反,在最极端的情况下Q所有的wchar_t都需?个char来表C,所以最大的可能是4倍加1?br>q两个函数在VC和gcc中都能正常运行(MinGW因ؓ前面说到的原因不支持宽字W的正常使用Q,在VC中会l出不安全的警告Q这是告诉给那些弄不清宽H{换实质的人的警告Q对于了解到目前q些知识的你我来_q就是啰嗦了?

lf426 2010-06-26 11:17 发表评论
]]>
d解密C++宽字W:2、Unicode和UTFhttp://www.shnenglu.com/lf426/archive/2010/06/25/118739.htmllf426lf426Fri, 25 Jun 2010 13:51:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/25/118739.htmlhttp://www.shnenglu.com/lf426/comments/118739.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/25/118739.html#Feedback0http://www.shnenglu.com/lf426/comments/commentRss/118739.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/118739.html" href_cetemp="http://www.163pan.com/files/c0x000k09.html"><本文PDF文档下蝲>

Unicode和UCS

Unicode和UCS是两个独立的l织分别制定的一套编码标准,但是因ؓ历史的原因,q两套标准是完全一L(fng)。Unicodeq个词用得比较多的原因可能是因ؓ比较Ҏ(gu)CQ如果没有特别的声明Q在本文所提及的Unicode和UCS是一个意思。Unicode的目标是建立一套可以包含hcL有语a文字W号你想得到想不到的各种东西的编码,其编码容量甚至预留了火星语以及银河系以外语言的空间——开个玩W,反正单的_Unicode~码集够的大,如果用计机单位来表C,其数量比3个字节大一些,不到4个字节?br>
Unicode和UTF

因ؓUnicode包含的内容太多,其编码在计算Z的表C方法就成ؓ了一个有必要研究的问题。传l编码,比如标准?位ASCIIQ在计算Z的表C方法就是占一个字节的?位,q似乎是不需要解释就W合大家?fn)惯的表C方法。但是当今Unicode的L辑ֈ32位(计算机的最单位是字节Q所以大?字节Q就只能臛_?字节表示Q,对于大部分常用字W,比如Unicode~码只占一个字节大的p字母Q占两个字节大小汉字Q都?个字节来储存太奢侈了。另外,如果都用4字节直接表示Q就不可避免的出Cؓ0的字节。而我们知道,在C语言中,0x00的字节就?\0'Q表C的是一个字W串Qchar字符Ԍ非wchar_tQ的l束Q换句话_C风格的char字符串无法表CUnicode?br>因ؓcM的种U问题,为Unicode在计机中的~码Ҏ(gu)出现了,q就是UTFQ所对应的,为UCS~码实现的方式也有自q说法。一般来_UTF-xQx表示q套~码一个单位至占用x位,因ؓUnicode最长达?2位,所以UTF-x通常是变长的——除了UTF-32Q而UCS-y表示一个单位就占用y个字节,所以能表示当今Unicode的UCS-y只有UCS-4Q但是因为历史的原因Q当Unicodeq没那么庞大的时候,2个字节够表C,所以有UCS-2Q现在看来,UCS-2所能表C的Unicode只是当今Unicode的一个子集?br>也就是说Q如果某U编码,能根据一定的规则法Q得到Unicode~码Q那么这U编码方式就可以UC为UTF?br>
UTF-8和W(xu)indows GB2312

UTF-8是一?#8220;聪明”的编码,可能?Q?Q?Q?个字节表C。通过UTF-8的算法,每一个字节表C的信息都很明确Q这是不是某个Unicode~码的第一个字节;如果是第一个字节,q是一个几位Unicode~码。这U?#8220;聪明”被称为UTF-8的自我同步,也是UTF-8成ؓ|络传输标准~码的原因?br>另外QUTF-8也不会出?字节Q所以可以表CZؓchar字符Ԍ所以可以成为系l的~码。Linuxpȝ默认使用UTF-8~码?br>Windows GB2312一般自UCؓGB2312Q其实真正的名字应该是Windows Codepage 936Q这也是一U变长的~码Q?个字节表CZl的ASCII部分Q汉字部分是两个字节的GBKQ国标扩Q展Q,拼音声母Q。Codepage 936也可以表CZؓchar字符Ԍ是中文Windowspȝ的默认编码?br>我们在第1节中看到?br>const char* s = "中文abc";
在Windows中的~码是Codepage 936Q在Linux中的~码是UTF-8?br>需要注意的是,Codepage 936不像UTFQ跟Unicode没有换算的关p,所以只能通过“代码?#8221;技术查表对应?br>
UTF-16和UCS-2

UTF-16?个字节或?个字节表C。在2个字节大的时候,跟UCS-2是一L(fng)。UTF-16不像UTF-8Q没有自我同步机Ӟ所以,~码大位在前q是位在前Q就成了见仁见智的问题。我们在W?节中Q?#8220;?#8221;的UCS-2BEQ因为是两个字节Q所以也是UTF-16BEQ编码是0x4E2DQ这里的BE是大位在后的意思(也就是小位在前了Q,对应的,如果是UCS-2LEQ编码就成了0x2D4E?br>Windows中的wchar_t是采用UCS-2BE~码。需要指出的是,C++标准中对wchar_t的要求是要能表示所有系l能识别的字W。Windows自称支持UnicodeQ但是其wchar_t却不能表C所有的UnicodeQ由此违背了C++标准?br>
UTF-32和UCS-4

UTF-32在目前阶D늭价于UCS-4Q都用定长的4个字节表C。UTF-32同样存在BE和LE的问题。Linux的wchar_t~码是UTF-32BE。在16位以内的时候,UTF-32BE的后两位Q前两位?x00 0x00Q等价于UTF-16BE也就{h(hun)于UCS-2BE

BOM

Z说明一个文仉用的是什么编码,在文件最开始的部分Q可以有BOMQ比?xFE 0xFF表示UTF-16BEQ?xFF 0xFE 0x00 0x00表示UTF-32LE。UTF-8原本是不需要BOM的,因ؓ其自我同步的Ҏ(gu),但是Z明确说明q是UTF-8Q而不是让文本~辑器去猜)Q也可以加上UTF-8的BOMQ?xEF 0xBB 0xBF

以上内容都讲q得很概略,详细信息h阅维基百U相兛_宏V?

lf426 2010-06-25 21:51 发表评论
]]>
d解密C++宽字W:1、从char到wchar_thttp://www.shnenglu.com/lf426/archive/2010/06/25/118707.htmllf426lf426Fri, 25 Jun 2010 06:41:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/25/118707.htmlhttp://www.shnenglu.com/lf426/comments/118707.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/25/118707.html#Feedback1http://www.shnenglu.com/lf426/comments/commentRss/118707.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/118707.html" href_cetemp="http://www.163pan.com/files/c0x000k09.html"><本文PDF文下蝲>

“q个问题比你惌中复?#8221;
Q我也学下BS的风|虽然q句话是我自׃(f)时想说的。^^Q?br>
从字W到整数

char是一U整数类型,q句话的含义是,char所能表C的字符在C/C++中都是整数类型。好Q接下来Q很多文章就会DZ个典型例子,比如Q?a'的数值就?x61。这U说法对吗?如果你细心的读过K&R和BS对于C和C++描述的原著,你就会马上反驳道Q?x61只是'a'的ASCII|q没有Q何规定C/C++的char值必d应ASCII。C/C++甚至没有规定char占几位,只是规定了sizeof(char){于1?br>当然Q目前大部分情况下,char?位的Qƈ且,在ASCII范围内的|与ASCII对应?br>
本地化策略集QlocaleQ?br>
“?a'译?x61的整数?#8221;Q?#8220;ASCII范围内的~码与char的整数值对应v?#8221;Q类DL(fng)规定Q是特定pȝ和特定编译器制定的,C/C++中有个特定的名词来描q这U规定的集合Q本地化{略集(locale。也有翻译成“现场”Q。而翻译——也是代码转换QcodecvtQ只是这个集合中的一个,C++中定义ؓ{略Qfacet。也有翻译ؓ“刻面”Q?br>
C/C++的编译策?br>
“本地化策略集”是个很好的概念,可惜在字W和字符串这个层面上QC/C++q不使用QC++的locale通常只是影响(streamQ)QC/C++使用更直接简单的{略Q硬~码?br>单的_字符Q串Q在E序文gQ可执行文gQ非源文Ӟ中的表示Q与在程序执行中在内存中的表CZ致。考虑两种情况Q?br>A、char c = 0x61;
B、char c = 'a';
情况A(ch)下,~译器可以直接认识作为整数的cQ但是在情况B下,~译器必d'a'译成整数。编译器的策略也很简单,是直接d字符Q串Q在源文件中的编码数倹{比如:
const char* s = "中文abc";
q段字符串在GB2312QWindows 936Q,也就是我们的windows默认中文pȝ源文件中的编码ؓQ?br>0xD6   0xD0   0xCE 0xC4 0x61 0x62 0x63
在UTF-8Q也是Linux默认pȝ源文件中的编码ؓQ?br>0xE4   0xB8   0xAD   0xE6   0x96   0x87   0x61   0x62   0x63
一般情况下Q编译器会忠实于源文件的~码为s赋|例外的情冉|如VC会自作聪明的把大部分其他cd~码的字W串转换成GB2312Q除了像UTF-8 without signatureq样的幸存者)?br>E序在执行的时候,s也就保持是这L(fng)~码Q不会再做其他的转换?br>
宽字W?wchar_t
正如char没有规定大小Qwchar_t同样没有标准限定Q标准只是要求一个wchar_t可以表示Mpȝ所能认识的字符Q在win32中,wchar_t?6位;Linux中是32位。wchar_t同样没有规定~码Q因为Unicode的概忉|们后面才解释Q所以这里只是提一下,在win32中,wchar_t的编码是UCS-2BEQ而Linux中是UTF-32BEQ等价于UCS-4BEQ,不过单的_?6位以内,一个字W的q?U编码值是一L(fng)。因此:
const wchar_t* ws = L"中文abc";
的编码分别ؓQ?br>0x4E2D   0x6587    0x0061   0x0062   0x0063                                                //win32Q?6?br>0x00004E2D   0x00006587    0x00000061   0x00000062   0x00000063        //LinuxQ?2?br>大写的L是告诉编译器Q这是宽字符丌Ӏ所以,q时候是需要编译器Ҏ(gu)locale来进行翻译的?br>比如Q在Windows环境中,~译器的译{略是GB2312到UCS-2BEQLinux环境中的{略是UTF-8到UTF-32BE?br>q时候就要求源文件的~码与编译器的本地化{略集中代码译的策略一_例如VC只能dGB2312的源代码Q这里还是例外,VC太自作聪明了 Q会很多其他代码在~译时自动{换成GB2312Q,而gcc只能dUTF-8的源代码Q这里就有个尬QMinGWq行win32下,所以只有GB2312pȝ才认Q而MinGW却用gcc~写Q所以自己只认UTF-8Q所以结果就是,MinGW的宽字符被废掉了Q?br>宽字W(Ԍq译器译Q还是被编码进E序文g中?

lf426 2010-06-25 14:41 发表评论
]]>
q代器(iteratorQ“擦”(eraseQ出的错?/title><link>http://www.shnenglu.com/lf426/archive/2010/06/10/117545.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Thu, 10 Jun 2010 03:03:00 GMT</pubDate><guid>http://www.shnenglu.com/lf426/archive/2010/06/10/117545.html</guid><wfw:comment>http://www.shnenglu.com/lf426/comments/117545.html</wfw:comment><comments>http://www.shnenglu.com/lf426/archive/2010/06/10/117545.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lf426/comments/commentRss/117545.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lf426/services/trackbacks/117545.html</trackback:ping><description><![CDATA[<p>设计一D|C程序:打印n个数字,然后指定擦掉其中的某一个,重新打印剩下的数字?/p> <div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br>#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">vector</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000"> std::cout;<br></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000"> std::cin;<br></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000"> std::endl;<br></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000"> std::vector;<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> argc, </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> argv[])<br>{<br>    </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> MAX </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">;<br>    vector</span><span style="COLOR: #000000"><</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"> v;<br>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; i </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> MAX; i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">) {<br>        v.push_back(i);<br>        cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> v[i] </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">\t</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">;<br>    }<br><br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> ers </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br>    </span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000"> ( ers </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> ers </span><span style="COLOR: #000000">>=</span><span style="COLOR: #000000"> MAX) {<br>        cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Erase No.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>        cin </span><span style="COLOR: #000000">>></span><span style="COLOR: #000000"> ers;<br>    }<br><br>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (vector</span><span style="COLOR: #000000"><</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">></span><span style="COLOR: #000000">::const_iterator i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> v.begin(); i </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> v.end(); i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">) {<br>        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">i </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> ers) {<br>            v.erase(i);<br>        }<br>    }<br><br>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (vector</span><span style="COLOR: #000000"><</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">></span><span style="COLOR: #000000">::const_iterator i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> v.begin(); i </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> v.end(); i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">) {<br>        cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">i </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">\t</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">;<br>    }<br>    cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> endl;<br><br>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div> q个E序看似没什么错误,可以利~译Q也可以利q行Q甚臻I大部分情况下可可以正常完成?br>我们q里讄的n?0QMAXQ,事实上,我们擦掉0?都没有问题,但是Q我们要擦掉9的时候,E序却出错了Q?br>在我们遍历查扑֯{值的循环中,一开始v.end()指向W?0个元素(数gؓ9Q的后面一个位|(不存在的W?1个元素的位置Q。当q代器指向第10个元素(数gؓ9Q的时候,v.erase()生效q行Q下一轮@环中QP代器本来应该指向W?1个元素的位置Qƈ且等于v.end()q结束@环。但是,因ؓ我们擦掉了vector中的一个元素,v.end()指向的是现在的最后一个元素——第9个元素的后面Q也是W?0个元素的位置。这Pq代器到?1Q而判断确是其是否?0Q这永q无法实玎ͼ形成了一个逻辑bugQ所以系l抛出错误了?br>一个修正的办法是把需要擦掉的q代器找出来Q在循环l束后再擦掉Q下面修改后的程序就可以正常的擦?了?br> <div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br>#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">vector</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000"> std::cout;<br></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000"> std::cin;<br></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000"> std::endl;<br></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000"> std::vector;<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> argc, </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> argv[])<br>{<br>    </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> MAX </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">;<br>    vector</span><span style="COLOR: #000000"><</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"> v;<br>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; i </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> MAX; i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">) {<br>        v.push_back(i);<br>        cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> v[i] </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">\t</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">;<br>    }<br><br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> ers </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br>    </span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000"> ( ers </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">||</span><span style="COLOR: #000000"> ers </span><span style="COLOR: #000000">>=</span><span style="COLOR: #000000"> MAX) {<br>        cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Erase No.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>        cin </span><span style="COLOR: #000000">>></span><span style="COLOR: #000000"> ers;<br>    }<br><br>    vector</span><span style="COLOR: #000000"><</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">></span><span style="COLOR: #000000">::const_iterator ers_i;<br>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (vector</span><span style="COLOR: #000000"><</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">></span><span style="COLOR: #000000">::const_iterator i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> v.begin(); i </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> v.end(); i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">) {<br>        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">i </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> ers) {<br>            ers_i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> i;<br>        }<br>    }<br>    v.erase(ers_i);<br><br>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (vector</span><span style="COLOR: #000000"><</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">></span><span style="COLOR: #000000">::const_iterator i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> v.begin(); i </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> v.end(); i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">) {<br>        cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">i </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">\t</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">;<br>    }<br>    cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> endl;<br><br>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div> <img src ="http://www.shnenglu.com/lf426/aggbug/117545.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lf426/" target="_blank">lf426</a> 2010-06-10 11:03 <a href="http://www.shnenglu.com/lf426/archive/2010/06/10/117545.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用对象的成员函数引出U程Q还是在U程中创建对象?http://www.shnenglu.com/lf426/archive/2010/06/05/117242.htmllf426lf426Sat, 05 Jun 2010 13:06:00 GMThttp://www.shnenglu.com/lf426/archive/2010/06/05/117242.htmlhttp://www.shnenglu.com/lf426/comments/117242.htmlhttp://www.shnenglu.com/lf426/archive/2010/06/05/117242.html#Feedback0http://www.shnenglu.com/lf426/comments/commentRss/117242.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/117242.html之所以提出TestClass2q种c,是因为在实际~程中我们会遇到q种情况Q我们不可预知这个类何时创徏以及创徏多少Q这个类的对象是一个新U程的参数。比如,在sokcet中的TCP server端就会有q种情况Q如果每一个新q接的client都用创徏一个新的线E去处理Q我们不可预知在什么时候会有多客L(fng)q过来?br>我们先观察没有多U程的时候对象的生命周期Q?br>
#include <iostream>
#include 
"windows.h"

class TestClass1{
private:
    
int x;
public:
    
explicit TestClass1(int to_x):x(to_x)
    {}
    
~TestClass1()
    {
        std::cerr 
<< "destruction: 1." << std::endl;
    }
    
void show() const
    {
        std::cerr 
<< x << std::endl;
    }
};

class TestClass2{
private:
    
int* pX;
public:
    
explicit TestClass2(int to_x)
    {
        pX 
= new int;
        
*pX = to_x;
    }
    
~TestClass2()
    {
        delete pX;
        std::cerr 
<< "destruction: 2."  << std::endl;
    }
    
const int& value() const
    {
        
return *pX;
    }
};

DWORD WINAPI thread_func(LPVOID pN)
{
    Sleep(
200);
    TestClass1 test((
*((TestClass2*)pN)).value());
    test.show();
    
return 0;
}

int main(int argc, char* argv[])
{
    
for (int i = 0; i < 3++i) {
        TestClass2 n(
5);
        
        thread_func((LPVOID)
&n);
        std::cerr 
<< "loop: " << i+1 << std::endl;
    }

    Sleep(
2000);

    std::cout 
<< "main() ok." << std::endl;

    
return 0;
}
q是标准的C++模式Q对象的生命周期是可以预见的Q?br>
5
destruction: 
1.
loop: 
1
destruction: 
2.
5
destruction: 
1.
loop: 
2
destruction: 
2.
5
destruction: 
1.
loop: 
3
destruction: 
2.
main() ok.
hL键l? . .
如果我们Ҏ(gu)U程调用Q?br>
#include <iostream>
#include 
"windows.h"

class TestClass1{
private:
    
int x;
public:
    
explicit TestClass1(int to_x):x(to_x)
    {}
    
~TestClass1()
    {
        std::cerr 
<< "destruction: 1." << std::endl;
    }
    
void show() const
    {
        std::cerr 
<< x << std::endl;
    }
};

class TestClass2{
private:
    
int* pX;
public:
    
explicit TestClass2(int to_x)
    {
        pX 
= new int;
        
*pX = to_x;
    }
    
~TestClass2()
    {
        delete pX;
        std::cerr 
<< "destruction: 2."  << std::endl;
    }
    
const int& value() const
    {
        
return *pX;
    }
};

DWORD WINAPI thread_func(LPVOID pN)
{
    Sleep(
200);
    TestClass1 test((
*((TestClass2*)pN)).value());
    test.show();
    
return 0;
}

int main(int argc, char* argv[])
{
    
for (int i = 0; i < 3++i) {
        TestClass2 n(
5);
        
        HANDLE hThrd;
        DWORD thrdId;
        hThrd 
= CreateThread(    NULL,
                                
0,
                                thread_func,
                                (LPVOID)
&n,
                                
0,
                                
&thrdId);
        
        std::cerr 
<< "loop: " << i+1 << std::endl;
    }

    Sleep(
2000);

    std::cout 
<< "main() ok." << std::endl;

    
return 0;
}
可以看到函数q回了错误的|至于Z么每ơ都?6我还不清楚,但是臛_不是正确的数?Q,q是因ؓ在线E调用TestClass2的对象之前已l被析构的缘故?br>
loop: 1
destruction: 
2.
loop: 
2
destruction: 
2.
loop: 
3
destruction: 
2.
36
destruction: 
1.
36
destruction: 
1.
36
destruction: 
1.
main() ok.
hL键l? . .
所以,如果我们设想构造一个类Q这个类的对象可以调用包含this的线E,那么q个对象一定不能是局部变量,或者说Q我们必d循环的{}对之前先把这些对象构造出来。这与我们的需求不W合——我们ƈ不知道需要多对象以及如何构造(比如构造TCP的通讯socket需要accept()接受客户端的信息Q,在这U情况下Q我们只能在U程中去构造对象,q样的对象生命周期跟U程函数一栗?br>或者说Q如果我们希望用cL装U程Q那么这些可以调用线E的对象必须是全局的。相兛_容请参考本人前面的教程“初试多线E?#8221;{?

lf426 2010-06-05 21:06 发表评论
]]>
在多U程中抛出的异常出错Q?/title><link>http://www.shnenglu.com/lf426/archive/2010/06/05/117241.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Sat, 05 Jun 2010 12:16:00 GMT</pubDate><guid>http://www.shnenglu.com/lf426/archive/2010/06/05/117241.html</guid><wfw:comment>http://www.shnenglu.com/lf426/comments/117241.html</wfw:comment><comments>http://www.shnenglu.com/lf426/archive/2010/06/05/117241.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lf426/comments/commentRss/117241.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lf426/services/trackbacks/117241.html</trackback:ping><description><![CDATA[以下以win32q_Z。我们先看一个非多线E的E序Q?br> <div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br>#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">windows.h</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br><br>DWORD WINAPI thread_func(LPVOID pN)<br>{<br>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; i </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">((</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)pN); </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">i) {<br>        std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> i</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\t</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>    }<br>    std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<br>    </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ok.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br><br>    std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">thread_func() done.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<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">int</span><span style="COLOR: #000000"> main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> argc, </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> argv[])<br>{<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> n </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">;<br><br>    </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000">{<br>    thread_func((LPVOID)</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">n);<br>    Sleep(</span><span style="COLOR: #000000">2000</span><span style="COLOR: #000000">);<br>    }<br>    </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> s) {<br>        std::cerr </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> s </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<br>        exit(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br>    }<br><br>    std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">main() done.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<br><br>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div> 可以看到Q函数thread_func()可以正确的抛出异常ƈ被main()的catch捕捉。但是,如果用一个新U程来运行thread_func()会出C么情况呢Q?br> <div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br>#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">windows.h</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br><br>DWORD WINAPI thread_func(LPVOID pN)<br>{<br>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; i </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">((</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)pN); </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">i) {<br>        std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> i</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\t</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>    }<br>    std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<br>    </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ok.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br><br>    std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">thread_func() done.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<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">int</span><span style="COLOR: #000000"> main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> argc, </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> argv[])<br>{<br>    HANDLE hThrd;<br>    DWORD thrdId;<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> n </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">;<br><br>    </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000">{<br>    hThrd </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> CreateThread(    NULL,<br>                            </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br>                            thread_func,<br>                            (LPVOID)</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">n,<br>                            </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br>                            </span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">thrdId);<br>    Sleep(</span><span style="COLOR: #000000">2000</span><span style="COLOR: #000000">);<br>    }<br>    </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> s) {<br>        std::cerr </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> s </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<br>        exit(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br>    }<br><br>    std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">main() done.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<br><br>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div> 很不q,q个E序~译的时候是可以通过的,但是q行时出错:<br> <div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">1</span><span style="COLOR: #000000">       </span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">       </span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">       </span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">       </span><span style="COLOR: #000000">5</span><span style="COLOR: #000000"><br><br>This application has requested the Runtime to terminate it </span><span style="COLOR: #0000ff">in</span><span style="COLOR: #000000"> an unusual way.<br>Please contact the application</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">s support team for more information.</span><span style="COLOR: #000000"><br></span><span style="COLOR: #000000">hL键l? . .</span></div> 而且同时会有一个运行时错误的提C。事实上Q这个错误提C意味着E序在没有发现try{}的时候看Cthrow?br>通过试验Q我发现pȝQ这里是win32Q不能将CreateThread()所产生的线E归l到try{}中。更加严重的情况是,即用一个函数囊括了整个E序Q然后tryq个函数Q其他线E依然脱Mq个try?br>所以,一个解x法是Q凡是遇到新的线E,必须在新U程中重新写异常处理。不Ӟ如google代码标准里所说的那样Q不使用C++的异常机制。毕竟C++没有定义多线E的标准Q所以也无从说起多U程中异常处理的标准?br>最后附上在新线E写异常处理的参考:<br> <div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br>#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">windows.h</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br><br>DWORD WINAPI thread_func(LPVOID pN)<br>{<br>    </span><span style="COLOR: #0000ff">try</span><span style="COLOR: #000000">{<br>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; i </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">((</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)pN); </span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">i) {<br>        std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> i</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\t</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>    }<br>    std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<br>    </span><span style="COLOR: #0000ff">throw</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">ok.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>    }<br>    </span><span style="COLOR: #0000ff">catch</span><span style="COLOR: #000000"> (</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> s) {<br>        std::cerr </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> s </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<br>        exit(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br>    }<br><br>    std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">thread_func() done.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<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">int</span><span style="COLOR: #000000"> main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> argc, </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> argv[])<br>{<br>    HANDLE hThrd;<br>    DWORD thrdId;<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> n </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">5</span><span style="COLOR: #000000">;<br><br>    hThrd </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> CreateThread(    NULL,<br>                            </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br>                            thread_func,<br>                            (LPVOID)</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">n,<br>                            </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br>                            </span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">thrdId);<br>    Sleep(</span><span style="COLOR: #000000">2000</span><span style="COLOR: #000000">);<br><br>    std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">main() done.</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<br><br>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div> <img src ="http://www.shnenglu.com/lf426/aggbug/117241.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lf426/" target="_blank">lf426</a> 2010-06-05 20:16 <a href="http://www.shnenglu.com/lf426/archive/2010/06/05/117241.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>函数指针与成员函数指?/title><link>http://www.shnenglu.com/lf426/archive/2008/04/26/48182.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Sat, 26 Apr 2008 04:39:00 GMT</pubDate><guid>http://www.shnenglu.com/lf426/archive/2008/04/26/48182.html</guid><wfw:comment>http://www.shnenglu.com/lf426/comments/48182.html</wfw:comment><comments>http://www.shnenglu.com/lf426/archive/2008/04/26/48182.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lf426/comments/commentRss/48182.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lf426/services/trackbacks/48182.html</trackback:ping><description><![CDATA[        游戏的设计离不开多线E,在C++新标准出来之前,多线E的设计q是多以依赖特定pȝ的函数库或者某些特定的函数库ؓ主,如同SDLQ打开多线E的函数也主要是C函数。我们当然很期待boost中真正意义上的C++多线E类的加入,不过仍然需要等待。问题就出在打开多线E的C函数上,因ؓ他们通常调用的是函数指针Q但是在C++中,我们通常把函数绑定到了与其数据相关的cMQ也是_我们在C++中很用?#8220;单n”的函敎ͼ成员函数可以被那些调用函数指针的启动多线E的函数调用吗?<br>        {案是:通常不行Q但是静态成员函C外?br>        在C++中,函数指针与成员函数指针完全是两个概念Qƈ且相互之间在M情况下,无法转换Q?br>        我们来看q么一个类Q?br> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> A<br>{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> a;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>    A(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> _a): a(_a)<br>    {}<br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> f1() </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>    {<br>        std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">call f1, a = </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> a </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<br>    }<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> f2() </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>    {<br>        std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">call f2, a = </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> a </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<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>    </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> f3(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> A</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> _a)<br>    {<br>        std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">call f3, </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>        _a.f1();<br>    }<br>    friend </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> f4(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> A</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> _a)<br>    {<br>        std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">call f4, a = </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> _a.a </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<br>    }<br>};</span></div> 其中函数A::f1()和A::f2()是毫无疑问的成员函数QA::f3()也是成员函数Q但是他是静态成员函敎ͼf4()是Acȝ友元函数Q他实际上就是一个普通的函数?br>A::f1()的指针我们需要这样定义:<br> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">typedef </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> (A::</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pcf)()</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;</span></div> 作ؓ参数的时候必这样写“&A::f1”?br>A::f2()的指针我们这样定义:<br> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">typedef </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> (A::</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">ptf)()</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;</span></div> 管A::f2()与A::f1()的返回类型不同,但是他们的Ş参列表是一L(fng)Q所以,指针可以通过强制转换q行转换?br>如果他们的Ş参列表不一_则强制{换在~译期间没有问题Q但是运行时会抛出异常?br>q是因ؓ形参列表不一h味着强制转换后,某些函数无法得到某些必须的参数。所以,q种转换应该是需要避免的?br>A::f3()和f4()管一个是静态成员函敎ͼ一个是普通函敎ͼ但是他们的指针定义却是一L(fng)Q?br> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">typedef </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pf)(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> A</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">);</span></div> q也是Z么调用函数指针的函数可以直接调用静态成员函数指针的原因?br>作ؓ参数的时候,他们既可以加?#8220;&”来写Q?#8220;&A::f3”, “&f4”Q?br>也可以不?#8220;&”Q?#8220;A::f3”, “f4”?br>q是在Acd义域外的情况。在A定义域内Q比如在写A的成员函数的时候,静态成员函数甚臛_以不需要加上A的定义域W号“A::”Q直接可以?#8220;&f3”或?#8220;f3”?br> <br>我们把剩下的E序补充完整Q?br> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> call_A(pcf pF, </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> A</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> _a)<br>{<br>    (_a.</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pF)();<br>}<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> call_A(pf pF, </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> A</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> _a)<br>{<br>    (</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pF)(_a);<br>}<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> argc, </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> argv[])<br>{<br>    A a(</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">);<br><br>    call_A(</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">A::f1, a);<br><br>    ptf __f2 </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">A::f2;<br>    pcf _f2 </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> (pcf)(__f2);<br>    call_A(_f2, a);<br><br>    call_A(A::f3, a);<br><br>    call_A(f4, a);<br><br>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div> 可以看到的情冉|Q?br>1、成员函数的指针与对象是不绑定的。也是_管我也很希望如果a是A的对象,a.f1()的指针要是能表示成a.f1Q或?#8220;&(a.f1)”Q多好?但是q是不允许的Q至现在是不允许的。我们要调用A::f1()Ҏ(gu)Q还得指定其对象Q所以,q实际上与调用静态成员函C普通函数是一L(fng)?br>2、静态成员函数可以代替普通函数被调用函数指针Q非成员函数指针Q的函数调用。但是静态成员函数有一个好处,是可以被类U有保护h——当Ӟ最好是有其他公共成员将其作用对外连接v来的时候? <img src ="http://www.shnenglu.com/lf426/aggbug/48182.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lf426/" target="_blank">lf426</a> 2008-04-26 12:39 <a href="http://www.shnenglu.com/lf426/archive/2008/04/26/48182.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>成员数据的三UŞ式与栈对象的生命周期http://www.shnenglu.com/lf426/archive/2008/04/14/47029.htmllf426lf426Mon, 14 Apr 2008 04:36:00 GMThttp://www.shnenglu.com/lf426/archive/2008/04/14/47029.htmlhttp://www.shnenglu.com/lf426/comments/47029.htmlhttp://www.shnenglu.com/lf426/archive/2008/04/14/47029.html#Feedback0http://www.shnenglu.com/lf426/comments/commentRss/47029.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/47029.html最直接的,我们可以把它定义ؓA的对象:A a_obj;
其次Q我们可以把它定义ؓA对象的引用:A& a_obj; 或者const引用Qconst A& a_obj;
再者,我们q可以把它定义ؓA对象的指针:A* pA_obj; 或者const对象的指针:const A* pA_obj;
        当我们直接用A对象的时候,a_obj会在B对象建立的时候徏立,在B销毁的时候销毁。因是一个新建立的对象,所以在成员初始化的时候是真正构造了对象Q即我们前面说到的用了复制构造函数?br>        如果使用的是A对象的引用或者指针,a_objQ或pA_objQ都没有构造新的对象。我们假设B的一个构造函数是q样的:B(const A& a_obj): a_obj(a_obj) {}Q那么毫无疑问,q个构造函数是能正常工作的Q也是_我们用现成的对象Q或者说是在B对象生命周期内都会一直存在的A对象L造B对象是没有问题的。但是,如果一个构造函数是q样的:B(int a): a_obj(A(a)) {}Q这个函敎ͼ一般在~译的时候是不会报错或者发告的Q但是我们分析一下,A(a)是(f)时构造了一个A对象Q然后a_obj成ؓ了这个(f)时对象的引用。但是问题是Q这个(f)时对象在B对象构造之后就马上销毁了Q也是_a_obj引用了一个不存在的对象(换到指针说就是指向了I指针)。这是一个巨大的错误Q将在运行时引发错误?br>        所以,l论是:如果成员数据使用Q新Q对象,则必d义这个对象所属类的复制构造函敎ͼ如果使用的是对象引用或者指针,则一定只能用已经存在q且会在B对象整个生命周期内都存在的A对象来构造这个B对象?br>        说得貌似很复杂,留个作ؓ例子?个类Q大家可以多写几个演C程序试试?br>
#ifndef A_HPP
#define A_HPP

#include 
<iostream>
using namespace std;

char* get_point(int lenth);
void free_point(char* temp);

class A
{
private:
    
//
protected:
    
char* temp;
    
int lenth;
    A();
public:
    A(
const A& copy);
    
~A();
    
void show() const;
};

class C: public A
{
public:
    C(
int _lenth);
    
~C();
};


class B
{
private:
    A b;
public:
    B(
const A& a);
    B(
int _lenth);
    
~B();
    
void show() const;
};

#endif

#include "a.hpp"

A::A(): temp(
0),lenth(0)
{
    cout
<< "A Constructor!" << endl; 
}


A::A(
const A& copy): lenth(copy.lenth)
{
    temp 
= get_point(lenth);
    cout 
<< "A Copy Constructor" << endl;
    cout 
<< "temp at: " << int(temp) << endl;
}


A::
~A()
{
    cout 
<< "temp at: " << int(temp) << endl;
    free_point(temp);
    cout 
<< "Heap Deleted!\n";
    cout 
<< "A Destroyed!" << endl; 
}

void A::show() const
{
    cout 
<< temp << endl;
}


//***************************************


C::C(
int _lenth): A()
{
    lenth 
= _lenth;
    temp 
= get_point(lenth);
    cout
<< "C Constructor!" << endl; 
    cout 
<< "temp at: " << int(temp) << endl;
}

C::
~C()
{
    cout 
<< "C Destroyed!" << endl; 
}

//***************************************

 
B::B(
const A& a): b(a)
{
    cout
<< "B Constructor!" << endl; 
}

B::B(
int _lenth): b(C(_lenth))
{
    cout
<< "B Constructor!" << endl;
}

B::
~B()
{
    cout 
<< "B Destroyed!" << endl; 
}

void B::show() const
{
    b.show();
}


//************************************


char* get_point(int lenth)
{
    
char* temp = new char[lenth+1];
    
for ( int i = 0; i< lenth; i++ )
        temp[i] 
= '*';
    temp[lenth] 
= '\0';
    cout 
<< "New buffer got!\n";
    
return temp;
}

void free_point(char* temp)
{
    delete []temp;
    cout 
<< "Buffer deleted!\n";
}


lf426 2008-04-14 12:36 发表评论
]]>
创徏一ơ销毁两ơ?Q复制构造函数的致命错误?/title><link>http://www.shnenglu.com/lf426/archive/2008/04/14/47025.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Mon, 14 Apr 2008 03:50:00 GMT</pubDate><guid>http://www.shnenglu.com/lf426/archive/2008/04/14/47025.html</guid><wfw:comment>http://www.shnenglu.com/lf426/comments/47025.html</wfw:comment><comments>http://www.shnenglu.com/lf426/archive/2008/04/14/47025.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/lf426/comments/commentRss/47025.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lf426/services/trackbacks/47025.html</trackback:ping><description><![CDATA[<p>        C++为我们提供了默认的复制构造函敎ͼ赋值函数和析构函数Q用的全部?#8220;复?#8221;Q即仅仅复制栈上的数据。换句话_如果我们涉及C对堆数据的操作,q些函数都必L们自己重新来写。我很郁闷ؓ什么在~译的时候,C++不能自己发现构造函C用了堆操作,从而提醒不要用默认的q三个函数。也许是因ؓ要编译器做到的判断很隑֐。用new...delete或许很容易看出来Q但是更多的函数调用Q特别是涉及到C风格的函数的时候,真的很难判断哪些函数使用C堆操作?br>        而这三个函数的作用可以说是巨大的Q析构就不说了,析构可以说是C++永远的痛。复制构造函数用得最多的地方Q恐怕就是成员初始化列表的时候,q几乎是在一个类成员数据使用到另外一个类对象时候的唯一Ҏ(gu)。而赋值函数则是把数据从语句体Q?#8220;{}”对,循环Q判断)中带出的最单方法——虽然我们现在可以很方便的用vector?br>        q里先说说复制构造函数吧。如果遗漏申明,又不慎用刎ͼ比如q个例子Q?/p> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br>#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">vector</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> A<br>{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> a;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>    A(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> _a): a(_a)<br>    {<br>        std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">A created!\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>    }<br></span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000"><br>    A(const A& copy): a(copy.a)<br>    {<br>        std::cout << "A copy created!\n";<br>    }<br></span><span style="COLOR: #008000">*/</span><span style="COLOR: #000000"><br>    </span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">A()<br>    {<br>        std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">A destroyed!\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>    }<br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> show() </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>    {<br>        std::cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> a </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> std::endl;<br>    }<br>};<br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> argc, </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> argv[])<br>{<br>    A a(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br>    A b(a);<br><br>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div> 那么Q结果运行就会出现貌似创Zơ,但是却销毁了两次的假象。这当然是不可能发生的,但是郁闷的是QC++中的构造和析构不L成对出现的,比如我们前面说到的手动显式调用析构函数的情况。所以,如果攑֜大的目中,qؓ我们的调试带来更多的困难?br>        所以,l论是,如果AcL造具有堆操作Q有可能把AcM为Bcȝ成员数据QBcd有可能通过成员初始化列表构造A对象Q请一定别忘记手写复制构造函数? <img src ="http://www.shnenglu.com/lf426/aggbug/47025.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lf426/" target="_blank">lf426</a> 2008-04-14 11:50 <a href="http://www.shnenglu.com/lf426/archive/2008/04/14/47025.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>昑ּ析构函数的陷?/title><link>http://www.shnenglu.com/lf426/archive/2008/04/12/46909.html</link><dc:creator>lf426</dc:creator><author>lf426</author><pubDate>Sat, 12 Apr 2008 06:29:00 GMT</pubDate><guid>http://www.shnenglu.com/lf426/archive/2008/04/12/46909.html</guid><wfw:comment>http://www.shnenglu.com/lf426/comments/46909.html</wfw:comment><comments>http://www.shnenglu.com/lf426/archive/2008/04/12/46909.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/lf426/comments/commentRss/46909.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/lf426/services/trackbacks/46909.html</trackback:ping><description><![CDATA[<p>        几乎在大部分时候,我们是不需要显式的调用析构函数的。显式的调用析构函数是一仉常危险的事情Q因为如果系l会调用析构函数Q无论我们自己是否已l调用过Q仍然会再次调用。换句话_我们自己所谓的昑ּ调用析构函数Q实际上只是调用了一个成员函敎ͼq没有真正意义上的让对象“析构”?br>        Z理解q个问题Q我们必首先弄明白“?#8221;?#8220;?#8221;的概c?br>堆区QheapQ?nbsp;—?一般由E序员分配释放, 若程序员不释放,E序l束时可能由O(jin)S回收 。注意它与数据结构中的堆是两回事Q分配方式倒是cM于链表?br>栈区QstackQ—?q译器自动分配释放 Q存攑և数的参数|局部变量的值等。其操作方式cM于数据结构中的栈?br>        我们构造对象,往往都是在一D语句体中,比如函数Q判断,循环Q还有就直接被一?#8220;{}”包含的语句体。这个对象在语句体中被创建,在语句体l束的时候被销毁。问题就在于Q这L(fng)对象在生命周期中是存在于栈上的。也是_如何理Q是pȝ完成而程序员不能控制的。所以,即我们调用了析构,在对象生命周期结束后Q系l仍然会再调用一ơ析构函敎ͼ其在栈上销毁,实现真正的析构?br>        所以,如果我们在析构函C有清除堆数据的语句,调用两次意味着W二ơ会试图清理已经被清理过了的Q根本不再存在的数据Q这是g会导致运行时错误的问题,q且在编译的时候不会告诉你Q?br>在网上找到这几句话,说得很好啊:<br><span style="COLOR: #666699">//昑ּ调用的时候,析构函数相当于的一个普通的成员函数<br>//~译器隐式调用析构函敎ͼ如分配了对内存,昑ּ调用析构的话引v重复释放堆内存的异常<br>//把一个对象看作占用了部分栈内存,占用了部分堆内存Q如果申请了的话Q,q样便于理解q个问题<br>//pȝ隐式调用析构函数的时候,会加入释放栈内存的动作(而堆内存则由用户手工的释放)<br>//用户昑ּ调用析构函数的时候,只是单纯执行析构函数内的语句Q不会释放栈内存Q摧毁对?/span><br>        pȝ在什么情况下不会自动调用析构函数呢?昄Q如果对象被建立在堆上,pȝ׃会自动调用。一个常见的例子是new...deletel合。但是好在调用delete的时候,析构函数q是被自动调用了。很|见的例外在于用布局new的时候,在delete讄的缓存之前,需要显式调用的析构函数Q这实在是很见的情c?br>        所以,l论是,一般不要自作聪明的去调用析构函数。或者要是你不嫌ȝ的话Q析构之前最好先看看堆上的数据是不是已经被释放过了。放Z个演C的例子Q大家可以参考一下哈?/p> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">#ifndef A_HPP<br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000"> A_HPP</span><span style="COLOR: #000000"><br><br>#include </span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">iostream</span><span style="COLOR: #000000">></span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">using</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">namespace</span><span style="COLOR: #000000"> std;<br><br></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> A<br>{<br></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> a;<br>    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> temp;<br>    </span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000"> heap_deleted;<br></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br>    A(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> _a);<br>    A(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> A</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> _a);<br>    </span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">A();<br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> change(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> x);<br>    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> show() </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">;<br>};<br><br></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000"><br></span></div> <p><br> </p> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">a.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><br>A::A(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> _a): heap_deleted(</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">)<br>{<br>    temp </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">;<br>    </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">temp </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> _a;<br>    a </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">temp;<br>    cout</span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">A Constructor!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> endl; <br>}<br><br>A::A(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> A</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000"> _a): heap_deleted(<span style="COLOR: #0000ff">false</span>)<br>{<br>    temp </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">;<br>    </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">temp </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> _a.a;<br>    a </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">temp;<br>    cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">A Copy Constructor</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> endl;<br>}<br><br>A::</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">A()<br>{<br>    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( heap_deleted </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">){<br>        cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">temp at: </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> temp </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> endl;<br>        delete temp;<br>        heap_deleted </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br>        cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Heap Deleted!\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>    }<br>    </span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"> {<br>        cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Heap  already Deleted!\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>    }<br><br>    cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">A Destroyed!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> endl; <br>}<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> A::change(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> x)<br>{<br>    a </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> x;<br>}<br><br></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> A::show() </span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"><br>{<br>    cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">a = </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> a </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> endl;<br>}</span></div> <br> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #000000">#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">a.hpp</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> main(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> argc, </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> argv[])<br>{<br><br>    A a(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br>    a.</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">A();<br>    a.show();<br>    cout </span><span style="COLOR: #000000"><<</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">main() end\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">;<br>    a.change(</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">);<br>    a.show();<br><br>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br>}</span></div> <img src ="http://www.shnenglu.com/lf426/aggbug/46909.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/lf426/" target="_blank">lf426</a> 2008-04-12 14:29 <a href="http://www.shnenglu.com/lf426/archive/2008/04/12/46909.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SDL入门教程Q九(ji)Q:4、int转换为std::stringhttp://www.shnenglu.com/lf426/archive/2008/03/26/45459.htmllf426lf426Wed, 26 Mar 2008 12:48:00 GMThttp://www.shnenglu.com/lf426/archive/2008/03/26/45459.htmlhttp://www.shnenglu.com/lf426/comments/45459.htmlhttp://www.shnenglu.com/lf426/archive/2008/03/26/45459.html#Feedback6http://www.shnenglu.com/lf426/comments/commentRss/45459.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/45459.html
        我下面考虑的问题,是用TextSurface反馈鼠标事g的信息。我惛_的第一个例子,很自然就是反馈鼠标所在坐标的位置。这里涉及到一个基的问题,即鼠标位|显然不是用字符串表C的。SDLl我们的反馈信息是intQ我们需要用TextSurfaceint构徏成可以被blit到ScreenSurface上的面,需要做的第一件事情,是将int转换为string?br>        我的思\是这L(fng)Q首先找到int的数位数Q然后依ơ从高位d数字Q之后将q个位去掉(通常减掉是最单的Q;依次记录q些数字Q{换成stringQ然后将q些数字“?#8221;Q字W串的合qӞh?br>头文件如下:
//UVi Soft (2008)
//Long Fei (lf426), E-mail: zbln426@163.com

//FileName: int_to_string.h

#ifndef INT_TO_STRING_H_
#define INT_TO_STRING_H_

#include 
<iostream>
#include 
<string>
#include 
<vector>

int int_power(int baseint exp);
std::
string int_to_string(int num);

#endif
        其中Qint_to_string()是我们需要构建的函数Qint_power()是求一个数的整数幂的函数。这么简单的法Q我们就自己写吧。至于用到vectorQ按照我的思\Q我们需要的数据l构昄应该?#8220;队列”Q先q先出)。不q真得感谢STLQ用vector昄不是最优化的,但是肯定是最“通俗”的,因ؓ即是作为非专业的队列(或者栈Q,vector也已lؓ我们提供了必要的Ҏ(gu)Q比如推入(push_backQ?br>        下面我就把程序说明夹在程序中间了。原因是本hp太菜Q简单描q还能忍Q描q算法就有点不能忍了-_-!!!。另外,管我英语这水^Q我q是希望E序里面别用中文注释的好。这U事情,(zhn)见q一ơؕ码,L得恶心一辈子?br>
//UVi Soft (2008)
//Long Fei (lf426), E-mail: zbln426@163.com

#include 
"int_to_string.h"

int int_power(int baseint exp)
{
    
int result = 1;
    
for (int i = exp; i > 0; i-- )
        result
*=base;
    
return result;
}
q是个很单的求幂的算法。其实我们在E序中,只需要用到求10的nơ幂Q所以,实际上我们还可以写得更加有针对一炏V?br>
std::string int_to_string(int num)
{
    
bool negative = false;
    
if ( num < 0 ){
        negative 
= true;
        num 
= -num;
    }
q开始写转换函数了。首先我们判定int是否。如果是Q我们把它变成其相反敎ͼ然后与正C栯{换,最后在前面加上“-”O(jin)K了?br>
    int bitNum = 1;
    
for ( int i = num; i > 9; i/=10 )
        bitNum
++;
bitNum是这个int的数位数。比?是1位,1024是4位?br>
    std::vector<int> eachNum;
    
for ( int i = bitNum, temp = num; i > 0; i-- ){
        
int highBit = int(temp/int_power(10, (i-1)));
        eachNum.push_back(highBit);
        temp
-=(highBit*int_power(10, (i-1)));
    }
我们通过vector数组U录每个C上的数字Q从高位C位。需要说明的是,n位的数字?0的n-1ơ方q。比?024?位,?000?0?ơ方q。所以,我们q里用的是i-1而非i?br>
    std::string str;
    
if ( negative == true )
        str 
= "-";
    
for ( std::vector<int>::iterator pTemp = eachNum.begin(); pTemp != eachNum.end(); pTemp++ ){
        
switch ( *pTemp ){
            
case 0:
                str
+="0";
                
break;
            
case 1:
                str
+="1";
                
break;
            
case 2:
                str
+="2";
                
break;
            
case 3:
                str
+="3";
                
break;
            
case 4:
                str
+="4";
                
break;
            
case 5:
                str
+="5";
                
break;
            
case 6:
                str
+="6";
                
break;
            
case 7:
                str
+="7";
                
break;
            
case 8:
                str
+="8";
                
break;
            
case 9:
                str
+="9";
                
break;
            
default:
                
break;
        }
    }
    
return str;
}
最后,我们用了STL的方法将每个数字转换成std::string的字W串Q然后将q些字符串合qv来,作ؓ函数的返回倹{?br>        我们在下一节中用TextSurface演示q个函数的作用,以及实现我们在本节前面所提出的问题?

lf426 2008-03-26 20:48 发表评论
]]>
从“集合”实例分析修饰函数返回值的const作用http://www.shnenglu.com/lf426/archive/2008/03/13/44360.htmllf426lf426Thu, 13 Mar 2008 05:30:00 GMThttp://www.shnenglu.com/lf426/archive/2008/03/13/44360.htmlhttp://www.shnenglu.com/lf426/comments/44360.htmlhttp://www.shnenglu.com/lf426/archive/2008/03/13/44360.html#Feedback3http://www.shnenglu.com/lf426/comments/commentRss/44360.htmlhttp://www.shnenglu.com/lf426/services/trackbacks/44360.html        发现q个问题Q是因ؓ一直以来思考的一个算法——关?#8220;集合”的实现。这个集合就是数学中的集合,与计机中数列一个最大的不同在于Q集合的元素是互异的。因两天在熟(zhn)vectorQ所以觉得用vector实现集合再合适不q了。STL实是很好很强大的体p,无论是内存管理,q是链表的实玎ͼ让我们可以省很多心。其实关于ؓ什么要实现集合Q也是因为我在计划实现类D雄无敌战移动的一pd法中,很多地方会用到集合的概念Q甚臛_括ƈ集和差集{等。也许我惛_的算法是很笨拙的Q但是在我还没有完全阅读相关的已有代码之前,觉得完全凭自q认识Q实现这些算法还是很有意义的Q所以,从学?fn)C++的第一天开始,我就在试图找到解册些问题的Ҏ(gu)Q而现在,来清CQ呵c?br>        我的思\很直接也很简单,是把一个数l中的元素往一个新的数l中填,新填充的元素会遍历新数组中已有的元素Q如果与之互异,则填入(pushQ,否则pC一个。以上就已经立了成员数据(U有Q和构造函数。因为我们需?#8220;集合?#8221;了的数组是可以被外部讉K的,所以一个最单的Ҏ(gu)是把成员数据公有——这实是很单,而且q样׃会出C天我们要讨论的问题了Q另外一个笨办法是用一个公有方法,q回成员数据的值——我是q么做的Q因貌似更符合OOP?#8220;数据隐藏”的精?_-!!!。很快可以写出头文gQ?br>
#ifndef AGGREGATE_H_
#define AGGREGATE_H_

#include 
<iostream>
#include 
<vector>
#include 
<algorithm>

class Aggregate
{
private:
    std::vector
<int> agg;
public:
    Aggregate(std::vector
<int>& temp);
    
const std::vector<int> getAgg() const;
};

#endif
h意那个红色的constQ其实我惌的是Q第一ơ写q个E序的时候,我ƈ没有q个const。一直以来,除了在重?#8220;=”的时候我大概清楚修饰q回值const的作用是可以避免让返回值做左|其他时候还真不太明白这个const的作用,只是本着C++的精——能constconst?_-!!!。实现文Ӟ
#include "aggregate.h"

Aggregate::Aggregate(std::vector
<int>& temp)
{
    
for ( std::vector<int>::iterator pTemp = temp.begin(); pTemp != temp.end(); pTemp++ ) {
        
bool findSame = false;
        
for ( std::vector<int>::iterator pAgg = agg.begin(); pAgg != agg.end(); pAgg++ )
            
if ( *pTemp == *pAgg )
                findSame 
= true;
        
if ( findSame == false )
            agg.push_back(
*pTemp);
    }
}

const std::vector<int> Aggregate::getAgg() const
{
    
return agg;
}
一切都很完,不是吗?手ql写Z个测试用的程序:
#include "aggregate.h"

void show(int& i);

int main(int argc, char* argv[])
{
    std::vector<int> tempArray;
    int temp;
    bool goon = true;

    while ( goon == true ) {
        std::cout << "#" << tempArray.size()+1 << "= ";
        std::cin >> temp;
        if ( temp == -1 ) {
            goon = false;
            continue;
        }
        tempArray.push_back(temp);
    }

    std::cout << "You've entered " << tempArray.size() << " numbers." << std::endl;

    for_each(tempArray.begin(), tempArray.end(), show);

    std::cout << "----------------------------\n" << "Now, to be aggregate\n";

    Aggregate tempAgg (tempArray);
    std::cout << "There are " << tempAgg.getAgg().size() << " different numbers.\n";
    for_each(tempAgg.getAgg().begin(), tempAgg.getAgg().end(), show);


    return 0;
}

void show(int& i)
{
    std::cout << i << std::endl;
}
很不q,~译正常的通过了(注意Q没有红色的const的时候)?br>但是Q运行时出现了错误?br>q行旉误是件o人很郁闷的事情,因ؓq意味着~译器不会帮你找到出错的地方?br>q运的是Q直觉让我觉得类似tempAgg.getAgg().begin()的用法有问题Q所以,我改成了Q(紫色那部分代码)
    std::cout << "----------------------------\n" << "Now, to be aggregate\n";

    Aggregate tempAgg (tempArray);
    std::vector
<int> tempAggArray = tempAgg.getAgg();
    std::cout 
<< "There are " << tempAggArray.size() << " different numbers.\n";
    for_each(tempAggArray.begin(), tempAggArray.end(), show);
q样Q问题是解决了。但是我们回头分析一下,刚才的问题到底出在什么地方呢Q?br>其实Q如果我们加上红色的constQ用原来的代码q行~译的时候,~译器是可以指出我们的错误的Q确实是tempAgg.getAgg().begin()的用法出了问题。具体的原因包含?lt;algorithm>里面Q我没有仔细d析,但是我们臛_明白了,Ҏ(gu)begin()会试图修改其对象的返回|
        让错误被发现在编译阶D,q远好于被发现在q行旉Dc我惻Iq就是C++中const最大的作用。所以,ȝhq是C++的一句话Q能constQ就const吧?)

lf426 2008-03-13 13:30 发表评论
]]>
ԸߺþþþþþþAAAAA| Ʒþþþù3d| ˾þô߽| ھƷþþþ| AëƬþþþƷëƬ| ƷþþþþҰ| רþۺϾĻ| þþþרav| ƷɫۺϾþ| þۺɫHEZYO| 99þùۺϾƷˮ| vaĻþ| һþۺ³³ŷһ | պһƵþ| ݺɫݺݺݺݺɫۺϾþ| þۺϾþڹ| þþþֻоƷ | þþƷۺһ| þù߳׽ѹۿ| Ʒþþþþþþ| þù| Ʒ˾þ˵Ӱ| ھƷþþþӰԺ| ƷþþþӰԺɫ| 777ҹƷþav| þþþþƷAV| þֻǾƷ66| ŷƷƵһþþþƷ | AëƬþ| þþƷž޾Ʒ| þþƷ޾Ʒ2020| ھƷþþþӰԺһ| þþ㽶ۺϼձ| ޾ƷƷþ99һ| ˾þۺϾƷAVר| ޾Ʒþǧն| ŷ츾XXXXԾþþ| ҹƷþþþþþþ| ٸþĻ| Ʒþþþþþþ| 18պҹþó|