国内精品人妻无码久久久影院导航 ,中文字幕久久精品无码,欧美午夜精品久久久久久浪潮http://www.shnenglu.com/xmli/category/8122.htmlぷ雪飄絳梅映殘紅 <br> &nbsp;&nbsp; ぷ花舞霜飛映蒼松<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;----- Do more,suffer lesszh-cnTue, 07 Dec 2010 14:14:45 GMTTue, 07 Dec 2010 14:14:45 GMT60C++多態技術(轉)http://www.shnenglu.com/xmli/archive/2010/12/07/135666.html李現民李現民Tue, 07 Dec 2010 02:52:00 GMThttp://www.shnenglu.com/xmli/archive/2010/12/07/135666.htmlhttp://www.shnenglu.com/xmli/comments/135666.htmlhttp://www.shnenglu.com/xmli/archive/2010/12/07/135666.html#Feedback0http://www.shnenglu.com/xmli/comments/commentRss/135666.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/135666.html閱讀全文

李現民 2010-12-07 10:52 發表評論
]]>
關于常量折疊(轉)http://www.shnenglu.com/xmli/archive/2010/11/23/134425.html李現民李現民Tue, 23 Nov 2010 13:24:00 GMThttp://www.shnenglu.com/xmli/archive/2010/11/23/134425.htmlhttp://www.shnenglu.com/xmli/comments/134425.htmlhttp://www.shnenglu.com/xmli/archive/2010/11/23/134425.html#Feedback0http://www.shnenglu.com/xmli/comments/commentRss/134425.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/134425.html

首先來看一個例子:

int main(int argc, char* argv[])
{
const int i=0;
int *j = (int *) &i;
*j=1;
cout<<&i<<endlcout<<j<<endl;
cout<<i<<endl;
cout<<*j<<endl;
return 0;
}

結果是

0012ff7c
0012ff7c

0

1

因為i和j都指向相同的內存地址,所以輸出的前兩個結果是相同的,但為啥相同的內存里的結果不相同么?--這就是常量折疊.

這個"常量折疊"是 就是在編譯器進行語法分析的時候,將常量表達式計算求值,并用求得的值來替換表達式,放入常量表。可以算作一種編譯優化。
我只是改了這個地址內容,但是i還是0,

因為編譯器在優化的過程中,會把碰見的const全部以內容替換掉(跟宏似的: #define pi 3.1415,用到pi時就用3.1415代替),這個出現在預編譯階段;但是在運行階段,它的內存里存的東西確實改變了!!!

6.網上的一些問題(4)


關于常量

這些天被常量的一些概念折磨著,現在終于有些明白了,

問題始于const int i = 10;//i存在哪,10存在哪

說明一:符號表

這個語句是對i的聲明,因為編譯器一開始就知道i的值,所以以后出現i時就會用10代替,這好像叫做符號表的概念,i就對應10了。

網上一篇帖子上有這樣的代碼:

const int a = 3;

int *p = const_cast<int *>(&a);

*p = 4;

cout << a;//仍然輸出3

這個結果可以用上面的說明來解釋

說明二:常量折疊(const folding)與復寫傳播 (copy propagation)

網上人們普遍反映thinking in c++將const folding譯為常量折疊是種誤導,我覺得譯的還行,本來folding就有折疊的意思,就是把原來的東西變小,而象const int i = 2*2;編譯器確實將2*2算成4了,以后碰到i就用4替換,這個計算2*2的過程據說叫常量折疊--const folding,而用4替換i的過程叫做復寫傳播--copy propagation.他們都是編譯器的優化技術


說明三:為常量分配空間

補充一下,這里說的都是const 定義的常量,而非文字常量,

(c++ primer翻譯成文字常量--literal constant

the c++ programming language(tcpl)翻譯成文字量,還分了不同類型)

至于文字常量存在哪,c++ primer 3ed上說它們是不可尋址的--nonaddressable,盡管它們也存在機器內存某個地方,但無法訪問它們的地址

對于int double等類型還好理解,但是對于字符串常量(tcpl里說將字符串文字量作為常量,利于存儲與訪問時的優化)下面的代碼似乎表示字符串常量存儲在靜態存儲區里(字符串文字量是靜態分配的--tcpl),那么字符串常量的地址不是可以訪問了嗎,在靜態存儲區里

http://bbs.bc-cn.net/dispbbs.asp?boardid=56&replyi...

字符串文字量的類型是常量字符數組--適當個數的const字符的數組

//有關字符常量的存儲區的問題

//另外,char a[]和char *a的區別

//"hello world 1"存在哪
#include <iostream>
using namespace std;
int main()
{


char* p = "hello world1";
char a[] = "hello world2";
//會為a在棧上分配13個字節的空間
// p[2] = a;
a[2] = a;
char* p1 = "hello world1"
printf("%xn",&p[2]);//p應該指向常量區
printf("%x",&a[2]);//棧上數組第三個元素的地址
return 0;
//結果42f036 //這是常量區
//12ff6e果然不一樣,這是棧區
}


6.總結

那么"常量折疊"到底是啥意思呢?

我理解,簡單的說就是,當編譯器處理const的時候,編譯器會將其變成一個立即數。

《thinking in c++》里面說這一點在數組定義里尤其重要(為啥呢?沒有查到相關的資料)。

Technorati : 



李現民 2010-11-23 21:24 發表評論
]]>
const靈異現象http://www.shnenglu.com/xmli/archive/2010/11/22/134275.html李現民李現民Mon, 22 Nov 2010 07:16:00 GMThttp://www.shnenglu.com/xmli/archive/2010/11/22/134275.htmlhttp://www.shnenglu.com/xmli/comments/134275.htmlhttp://www.shnenglu.com/xmli/archive/2010/11/22/134275.html#Feedback14http://www.shnenglu.com/xmli/comments/commentRss/134275.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/134275.htmlconst靈異現象

版本:0.1

最后修改:2010-11-22

撰寫:李現民


概述

constc++中意味著“不可改變”,但在有些情況下我們可以“合法”地繞過編譯器去修改一些const數據,比如const_cast就可以剝離一個對象的const屬性。然而,我們這樣做在多大程度上是“合理”的,卻因不同的問題而論,也許一不小心,你就可能掉入陷阱之中。

以下問題,我只分析,不說話,請各位看官自己判斷。


目標是一個常數

這件事源于在網上看到的一篇文章,其來源已經不可考,但大意是:就如下C++程序,其輸出是什么:

void foo()
{
const int a = 1;
int* p = const_cast<int*>(&a);
*p = 2;
printf(" a= %d\n *p= %d\n &a= %x\n p= %x \n\n", a, *p, &a, p);
}


我在VC2008下的實測結果為:

a = 1
*p = 2
&a = 12ff6c
p = 12ff6c


好了,問題出現:明明p所指向的就是變量a,但為何打印其值時a!=*p

這并非是我用錯了const_cast,也不是編譯器進行了優化的問題。事實上,在各版本的VCg++下的運行結果均是如此。

以下是VC2008debug版本的匯編代碼:

const int a = 1;
0041146E mov dword ptr [a],1
int* p = const_cast<int*>(&a);
00411475 lea eax,[a]
00411478 mov dword ptr [p],eax
*p = 2;
0041147B mov eax,dword ptr [p]
0041147E mov dword ptr [eax],2
printf(" a= %d\n *p= %d\n &a= %x\n p= %x \n\n", a, *p, &a, p);
00411484 mov esi,esp
00411486 mov eax,dword ptr [p]
00411489 push eax
0041148A lea ecx,[a]
0041148D push ecx
0041148E mov edx,dword ptr [p]
00411491 mov eax,dword ptr [edx]
00411493 push eax
00411494 push 1
00411496 push offset string " a=\t%d\n *p=\t%d\n &a=\t%x\n p=\t%x \n\n"... (415808h)
0041149B call dword ptr [__imp__printf (419318h)]


printf()的四個參數入棧過程中我們可以看出:指針p的確指向變量a了,而變量a處的數值也的確被改寫成2了,問題是:當壓入a的值的時候,編譯器直接壓入了其原始數值1

關鍵其實在于:const_cast所操作的目標是否為基礎數據類型(char, int, float, double等),如果是類(或結構體)對象則又將是另一番情形

當修改字符串常量

這個問題最早見于一篇文章《Solmyr的小品文系列之一:字符串放在哪里?》,在這里我只不過轉述一二。

代碼如下:

void foo()
{
char* str1 = "watch";
const char* str2 = "watch";
char str3[] = "watch";

str1
[0] = 'm';

std
::cout<< str1 << std::endl << str2 << std::endl << str3 << std::endl;
}


VC6Release版本運行結果如下:

match
match
watch

VC2008Release版本運行結果如下:

watch
watch
watch


容易看出:這段代碼的運行結果決定于編譯器,因為我們改寫了不應該被改寫的常量數據。更根本的原因是:由于編譯器優化,str1str2實際上指向的是同一份”watch”字符串

這還帶出了另一件事:盡管str1的聲明中不帶const,但它所指向的字符串數據隱含是const類型的

注意:這段代碼只有Release版本才能順利執行,Debug版版本運行時會得到一個Access violation






李現民 2010-11-22 15:16 發表評論
]]>
delete this--對象請求自殺http://www.shnenglu.com/xmli/archive/2009/08/18/93683.html李現民李現民Tue, 18 Aug 2009 03:07:00 GMThttp://www.shnenglu.com/xmli/archive/2009/08/18/93683.htmlhttp://www.shnenglu.com/xmli/comments/93683.htmlhttp://www.shnenglu.com/xmli/archive/2009/08/18/93683.html#Feedback0http://www.shnenglu.com/xmli/comments/commentRss/93683.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/93683.html

delete this--對象請求自殺

版本:0.1

最后修改:2009-08-18

撰寫:李現民


     第一次見delete this的時候,沒覺得這是一項會有什么特殊作用的技術,因此也就沒有特別關注。

     昨日在sourcemaking.com上看state模式之c++實現的時候,看到它在狀態轉換的時候使用了delete this,感覺似乎還不錯。

     作為一種“禁術”,使用的時候必須要相當小心才行,《C++ FAQ》里提到所謂“小心”至少包括以下幾個方面:

  1. this對象是必須是用 new操作符分配的(而不是用new[],也不是用placement new,也不是局部對象,也不是global對象);

  2. delete this后,不能訪問該對象任何的成員變量及虛函數(delete this回收的是數據,這包括對象的數據成員以及vtable,不包括函數代碼);

  3. delete this后,不能再訪問this指針。換句話說,你不能去檢查它、將它和其他指針比較、和 NULL比較、打印它、轉換它,以及其它的任何事情;


     個人認為保證以上禁忌列表基本手段可以包括:

  1. 析構函數私有化(如果有子類,則protected化,保證子類能夠正確繼承)--以保證對象必須使用new在堆上分配內存;

  2. 提供(可以在僅僅在基類中)Destroy(void)函數,里面僅有一句delete this--以保證第三方能夠將分配的內存回收;


     下一次使用state pattern的時候,我想可以嘗試一下。



李現民 2009-08-18 11:07 發表評論
]]>
給unsigned int 賦一個最大值http://www.shnenglu.com/xmli/archive/2009/02/06/73117.html李現民李現民Fri, 06 Feb 2009 08:37:00 GMThttp://www.shnenglu.com/xmli/archive/2009/02/06/73117.htmlhttp://www.shnenglu.com/xmli/comments/73117.htmlhttp://www.shnenglu.com/xmli/archive/2009/02/06/73117.html#Feedback2http://www.shnenglu.com/xmli/comments/commentRss/73117.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/73117.html
如果 unsigned int a; ,那么,你無法通過測試 if(a>0)測試出你賦給a的值到底是否是正的,因此,通常我們寧愿使用 int b; 配合 assert(a>=0);

不過,由于項目的需要(基于windows的,使用了太多的DWORD,不過DWORD的定義通常為unsigned long),其中還是使用了一些unsigned int,我發現項目中通常要求賦一個很大(最大)的初始值,用什么? 0xffffffff嘛? 我都記不住0x后面應該有幾個f,況且,我不能保證系統一定是32位的;

還是用 unsigned int a= -1;吧,就讓無符號整數為自己也做點貢獻吧。



李現民 2009-02-06 16:37 發表評論
]]>
std::map于vc6下的使用bughttp://www.shnenglu.com/xmli/archive/2009/02/03/72850.html李現民李現民Tue, 03 Feb 2009 02:40:00 GMThttp://www.shnenglu.com/xmli/archive/2009/02/03/72850.htmlhttp://www.shnenglu.com/xmli/comments/72850.htmlhttp://www.shnenglu.com/xmli/archive/2009/02/03/72850.html#Feedback3http://www.shnenglu.com/xmli/comments/commentRss/72850.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/72850.html
D:\me\document\VC6\test\test.cpp(34) : error C2146: syntax error : missing ',' before identifier 'test_map'
D:\me\document\VC6\test\test.cpp(34) : error C2065: 'test_map' : undeclared identifier
D:\me\document\VC6\test\test.cpp(34) : error C2143: syntax error : missing '>' before ';'

  于是改寫成如下代碼:
    typedef std::vector<int>            IntVector;
    typedef std::map<int, IntVector>    IntVectorMap;
    IntVectorMap test_map;


順利編譯通過 -_- 還真是邪門了。

注:std::map<int, std::vector<int>>  test_map; 在vs2005下順利編譯通過。





李現民 2009-02-03 10:40 發表評論
]]>
通用工廠類(generic factory class)http://www.shnenglu.com/xmli/archive/2008/10/22/64722.html李現民李現民Wed, 22 Oct 2008 10:48:00 GMThttp://www.shnenglu.com/xmli/archive/2008/10/22/64722.htmlhttp://www.shnenglu.com/xmli/comments/64722.htmlhttp://www.shnenglu.com/xmli/archive/2008/10/22/64722.html#Feedback2http://www.shnenglu.com/xmli/comments/commentRss/64722.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/64722.html  我記得《C++對話系列》中有一些相關的討論,于是我找來查看。非常幸運的,我發現這正是我需要的東西,于是幾乎照抄的把代碼實現了,代碼測試通過。為了符合我自己的閱讀習慣,我把其中的一個函數及變量的命名改動了一下:
  factory.hpp
#pragma once
#pragma warning (disable:
4786)
/********************************************************************
created:    2008-10-22
author:        lixianmin

purpose:    a generic factory method lib
reference:  《C++對話系列--Abstract Factory, Template Style》
Copyright (C) 2008 - All Rights Reserved
********************************************************************
*/
#include 
<string>
#include 
<map>
namespace lib
{
    
//通用工廠類,根據傳入的id創建產品對象
    template <typename BaseType, typename KeyType=std::string>
    
class factory
    {
    
private:
        typedef std::auto_ptr
<BaseType> (*BaseCreateFunc)();
        typedef std::map
<KeyType, BaseCreateFunc> FuncRegistry;
    
public:
        
static factory<BaseType, KeyType>& get_instance()        //static singleton,不適用于多線程
        {
            
static factory<BaseType, KeyType> obj;
            
return obj;
        }
        std::auto_ptr
<BaseType> create(const KeyType& id) const
        {
            std::auto_ptr
<BaseType> obj;
            FuncRegistry::const_iterator regEntry 
= _registry.find(id);
            
if (regEntry != _registry.end()) 
            {
                obj 
= regEntry->second();
            }
            
return obj;
        }
        
void _register_create_function(const KeyType& id, BaseCreateFunc func){_registry[id] = func;}
    
private:
        factory(
void){}
        factory(
const factory& other);
        factory 
operator=(const factory& other);
    
private:
        FuncRegistry _registry;
    };
    
//類型(DerivedType)注冊類,只要在DerivedType類定義(DerivedType.cpp文件)的最后聲明一個 lib::factory_register<Base, Derived> reg(id);對象即可
    template <typename BaseType, typename DerivedType, typename KeyType=std::string>
    
class factory_register
    {
    
public:
        factory_register(
const KeyType& id)
        {
            factory
<BaseType, KeyType>::get_instance()._register_create_function(id, _create_instance);
        }
    
private:
        
static std::auto_ptr<BaseType> _create_instance(){return std::auto_ptr<BaseType>(new DerivedType);}
    
private:
        friend 
class factory<BaseType, KeyType>;
    };
}

測試代碼:
#include <iostream>
#include 
"factory.hpp"
//基類
class Base
{
public:
    
virtual void print(void)
    {
        std::cout
<<"base class"<<std::endl;
    }
};
lib::factory_register
<Base, Base> reg1("base");            //注冊Base類型,定義一個file scope的變量,通常應該置于Base.cpp文件結尾
//派生類
class Derived:public Base
{
public:
    
virtual void print(void)
    {
        std::cout
<<"derived class"<<std::endl;
    }
};
lib::factory_register
<Base, Derived> reg2("derived");    //注冊Derived類型,定義一個file scope的變量,通常應該置于Derived.cpp文件結尾

//聲明一個全局函數(簡化操作,非必需)
lib::factory<Base>& glb_GetFactory(void)
{
    
return lib::factory<Base>::get_instance();
}
int main(int argc, char* argv[])
{
    std::auto_ptr
<Base> base=glb_GetFactory().create("base");
    
if (base.get())
    {
        
base->print();
    }
    std::auto_ptr
<Base> derived=glb_GetFactory().create("derived");
    
if (derived.get())
    {
        derived
->print();
    }

    system(
"pause");
    
return 0;
}
輸出:
base class
derived class
請按任意鍵繼續. . .






李現民 2008-10-22 18:48 發表評論
]]>
C++中對象生成及使用策略http://www.shnenglu.com/xmli/archive/2008/10/20/64471.html李現民李現民Mon, 20 Oct 2008 02:34:00 GMThttp://www.shnenglu.com/xmli/archive/2008/10/20/64471.htmlhttp://www.shnenglu.com/xmli/comments/64471.htmlhttp://www.shnenglu.com/xmli/archive/2008/10/20/64471.html#Feedback0http://www.shnenglu.com/xmli/comments/commentRss/64471.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/64471.html2、如果類的成員變量必須是指針對象的話,采用在構造函數中申請(new)并在析構函數中銷毀(delete)的辦法,避免memory leak;
3、定義數組時,使用向量:std::vector<char> vBuffer(nSize),而不要使用 char* a=new char[nSize];這樣可以讓容器替你維護這段內存;如果數組大小固定且應用簡單的話也可以使用固定長度的數組, 如char text[nSize];
4、很多教程都在談std::auto_ptr的好處,但在我的經驗中必須使用std::auto_ptr的地方很少,我只見過兩種:一是factory method返回動態對象指針時,為了保證內存釋放最好使用智能指針封裝;二是加載特別大的資源對象時,這種對象由于太大而不適合放在stack中;
5、使用傳引用方式傳參pass-by-reference(-to-const),避免使用傳指針pass-by-pointer的方式,這樣既可以免去指針判NULL的檢查,又可以在不失去對象所有權的前提下傳遞std::auto_ptr<...> 對象




李現民 2008-10-20 10:34 發表評論
]]>
Memento:ansi文件操作函數http://www.shnenglu.com/xmli/archive/2008/10/15/64048.html李現民李現民Wed, 15 Oct 2008 11:02:00 GMThttp://www.shnenglu.com/xmli/archive/2008/10/15/64048.htmlhttp://www.shnenglu.com/xmli/comments/64048.htmlhttp://www.shnenglu.com/xmli/archive/2008/10/15/64048.html#Feedback0http://www.shnenglu.com/xmli/comments/commentRss/64048.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/64048.html
#include <io.h>
#include 
<sys/stat.h>
int main(int argc, char* argv[])
{
    
const char* szPath="c:\\abc.txt";    
    
if (_access(szPath, 0))                            //測試文件是否存在,如果測試為真,則文件不存在
    {
        std::cout
<<szPath<<"--does not exist!"<<std::endl;
        
return -1;
    }

    
struct stat st;
    stat(szPath, 
&st);
    std::cout
<<"file size="<<st.st_size<<std::endl;    //獲取文件屬性(包括大小、創建時間、宿主等等)

    system(
"pause");
    
return 0;
}



李現民 2008-10-15 19:02 發表評論
]]>
datastream, C++數據序列化與反序列化容器http://www.shnenglu.com/xmli/archive/2008/10/15/64030.html李現民李現民Wed, 15 Oct 2008 06:55:00 GMThttp://www.shnenglu.com/xmli/archive/2008/10/15/64030.htmlhttp://www.shnenglu.com/xmli/comments/64030.htmlhttp://www.shnenglu.com/xmli/archive/2008/10/15/64030.html#Feedback0http://www.shnenglu.com/xmli/comments/commentRss/64030.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/64030.html閱讀全文

李現民 2008-10-15 14:55 發表評論
]]>
enum與對象狀態檢查http://www.shnenglu.com/xmli/archive/2008/09/27/62883.html李現民李現民Sat, 27 Sep 2008 03:44:00 GMThttp://www.shnenglu.com/xmli/archive/2008/09/27/62883.htmlhttp://www.shnenglu.com/xmli/comments/62883.htmlhttp://www.shnenglu.com/xmli/archive/2008/09/27/62883.html#Feedback0http://www.shnenglu.com/xmli/comments/commentRss/62883.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/62883.html  比如對錄音機Recorder這樣一個類而言,至少會有幾個狀態:數據加載Loading,數據保存Saving,數據加載完畢Loaded,數據錄制Recording,數據播放Playing等等,這些狀態往往是互斥的(但并不總是這樣),對Play()函數,必須Loaded=true,對Save函數,必須Recording=false
  狀態檢測的必要性在于:代碼的擴大(復雜化),新人參與的維護及狀態的更迭隨時有可能在出人意料的情況下調用到某些函數,這些函數可能在大多數情況下在這里調用是有意義的,但在某些極端的情況下卻可能造成數據破壞,因此在各函數入口處執行完善的狀態檢測是很有意義的。
  針對各種狀態可以維護一個對應的bool值,但寫一個enum附帶一個status數組可能更容易維護:
    enum
    {
        stLoaded,                  
//數據加載完畢
        stRecording,                //數據錄制中
        stReplaying,                //數據回放中
        stSize                       //狀態數組的大小
    };
    
bool                        m_aStatus[stSize];
   OK,這時可以在構造函數中執行std::fill(m_aStatus, m_aStatus+stSize, false);對所有的狀態進行初始化,特別是:你隨后可以任意地增減這個enum中狀態變量的數目或改動其名稱,同時均不需要擔心狀態變量初始化問題



李現民 2008-09-27 11:44 發表評論
]]>
不要在C++的.h文件中給出全局函數的定義式http://www.shnenglu.com/xmli/archive/2008/09/23/62595.html李現民李現民Tue, 23 Sep 2008 07:41:00 GMThttp://www.shnenglu.com/xmli/archive/2008/09/23/62595.htmlhttp://www.shnenglu.com/xmli/comments/62595.htmlhttp://www.shnenglu.com/xmli/archive/2008/09/23/62595.html#Feedback2http://www.shnenglu.com/xmli/comments/commentRss/62595.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/62595.html  把定義式放到.cpp文件中,在.h文件中僅僅保留全局函數的定義式,鏈接通過
  可是,這樣的函數是inline的嘛?在定義式那邊加上inline?待進一步探索



李現民 2008-09-23 15:41 發表評論
]]>
const對象只能調用const成員函數http://www.shnenglu.com/xmli/archive/2008/09/09/61359.html李現民李現民Tue, 09 Sep 2008 01:47:00 GMThttp://www.shnenglu.com/xmli/archive/2008/09/09/61359.htmlhttp://www.shnenglu.com/xmli/comments/61359.htmlhttp://www.shnenglu.com/xmli/archive/2008/09/09/61359.html#Feedback0http://www.shnenglu.com/xmli/comments/commentRss/61359.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/61359.html   以后注意


李現民 2008-09-09 09:47 發表評論
]]>
C++中std::set<>集合中元素比較器(less<>)的設計http://www.shnenglu.com/xmli/archive/2008/09/08/61282.html李現民李現民Mon, 08 Sep 2008 01:44:00 GMThttp://www.shnenglu.com/xmli/archive/2008/09/08/61282.htmlhttp://www.shnenglu.com/xmli/comments/61282.htmlhttp://www.shnenglu.com/xmli/archive/2008/09/08/61282.html#Feedback0http://www.shnenglu.com/xmli/comments/commentRss/61282.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/61282.html   假定需要設計的類為Country,各country之類比較的依據是人口population,分析如下:

   情形一:如果類Country類是你本人設計的,即你擁有對Country類的修改權,那么在類中重載operator<就可以了,需要注意的就是必須將其設計為const成員函數,如下:
class Country
{
public:
    
explicit Country(int population)
    {
        m_nPopulation
=population;
    }
    
void print()
    {
        std::cout
<<m_nPopulation<<std::endl;
    }
    
//注:operator<必須是const成員函數
    bool operator<(const Country& b)const
    {
        
return m_nPopulation<b.m_nPopulation;
    }

private:
    
int m_nPopulation;
};
int main(int argc, char* argv[])
{
    Country countryArray[]
={Country(43), Country(54),Country(85),Country(95),Country(12),Country(57),Country(124),Country(78),
        Country(
45), Country(56),Country(87),Country(457),Country(567),Country(123),Country(456),Country(237),
        Country(
43), Country(784),Country(728),Country(76),Country(467),Country(83),Country(723),Country(86)};
    std::
set<Country> countrySet;

    
int nSize=sizeof countryArray/ sizeof countryArray[0];
    
for (int i=0; i<nSize; ++i)
    {
        countrySet.insert(countryArray[i]);
    }

    
for (std::set<Country>::iterator iter=countrySet.begin(); countrySet.end()!=iter; ++iter)
    {
        iter
->print();
    }


    
//Sleep(int(2e9));
    system("pause");
    
return 0;
}

   情形二:Country為不是你設計的,即類中沒有已存在的operator<比較器,同時你也無法對其進行修改,那么你現在需要做的是在外部設計一個比較器,確切的說,是一個函數對象(或函數,但函數無法內聯),如下:

class Country
{
public:
    
explicit Country(int population)
    {
        m_nPopulation
=population;
    }
    
void print()
    {
        std::cout
<<m_nPopulation<<std::endl;
    }
    
//比上一個設計需要新加入一個函數
    int GetPopulation(voidconst
    {
        
return m_nPopulation;
    }
private:
    
int m_nPopulation;
};
int main(int argc, char* argv[])
{
    Country countryArray[]
={Country(43), Country(54),Country(85),Country(95),Country(12),Country(57),Country(124),Country(78),
        Country(
45), Country(56),Country(87),Country(457),Country(567),Country(123),Country(456),Country(237),
        Country(
43), Country(784),Country(728),Country(76),Country(467),Country(83),Country(723),Country(86)};

    
//設計函數對象
    struct country_less:public std::binary_function<Country, Country, bool>
    {
        
//這個倒不必須成為const成員函數,呵呵
        bool operator()(const Country& a, const Country& b)const
        {
            
return a.GetPopulation()<b.GetPopulation();
        }
    };
    
//std::set的定義就要復雜一些了
    std::set<Country, country_less> countrySet;

    
int nSize=sizeof countryArray/ sizeof countryArray[0];
    
for (int i=0; i<nSize; ++i)
    {
        countrySet.insert(countryArray[i]);
    }
    
//同樣,迭代器的定義也要復雜一些
    for (std::set<Country, country_less>::iterator iter=countrySet.begin(); countrySet.end()!=iter; ++iter)
    {
        iter
->print();
    }

    
//Sleep(int(2e9));
    system("pause");
    
return 0;
}

   這兩種情況的作用就是std::less<>謂詞,因此同樣適用于std::sort()











李現民 2008-09-08 09:44 發表評論
]]>
char, wchar_t與STL的字符串格式化formathttp://www.shnenglu.com/xmli/archive/2008/09/02/60663.html李現民李現民Tue, 02 Sep 2008 02:23:00 GMThttp://www.shnenglu.com/xmli/archive/2008/09/02/60663.htmlhttp://www.shnenglu.com/xmli/comments/60663.htmlhttp://www.shnenglu.com/xmli/archive/2008/09/02/60663.html#Feedback2http://www.shnenglu.com/xmli/comments/commentRss/60663.htmlhttp://www.shnenglu.com/xmli/services/trackbacks/60663.html   最近一直在寫序列化類,希望把一些游戲過程中的場景數據信息存儲到硬盤。因為需要處理的數據很多,所以我寫了一個工具類,其中包括字符串的序列化,問題來了:
   公司原先的代碼參差不齊,有使用AString的(使用ANSI char作為字符單元,相當于std::string),也有考慮到unicode問題而采用AWString的(使用wchar_t作為字符單元,相當于std::wstring),同時考慮到根據編譯環境自動視別的問題,也定義有一個宏ACString,即:如果定義有UNICODE環境變量,則自動替換為AWString,否則使用AString。好吧,自作聰明的我使用了ACString來寫工具函數,測試時沒有任何問題,但一旦加入到真正的運行環境中就會出現“把const char*轉化為bool,性能警告”的錯誤,幾經檢查,發現在游戲環境下,傳入的參數是AString類型,而我用的ACString則被自動轉化成了AWString,找不到參數匹配的,所以只有默認轉化了。
   看來,解決辦法只能是同時提供AString與AWString兩種類型的工具函數,因為你不知道你的客戶傳給你的將是哪一種,除非大家都鐵了心的一致使用ACString,然而在現實的編碼中,這卻是不切實際的。
   這讓我想起前兩天為STL寫的格式化函數(STL沒有,只好自己寫了-_-),當時我也想自作聰明的把std::string與std::wstring合二為一,現在想來恐怕是庸人自擾罷了,于是早上起來把原來的代碼作下修改,如下:
#include <stdarg.h>
#include 
<string>
#include 
<vector>
#include 
<cassert>

#ifndef __STR_STR_HPP_INCLUDED_
#define __STR_STR_HPP_INCLUDED_
namespace str
{
    
//字符串格式化函數
    std::string format(const char *fmt, 
    { 
        std::
string strResult="";
        
if (NULL != fmt)
        {
            va_list marker 
= NULL;            
            va_start(marker, fmt);                            
//初始化變量參數 
            size_t nLength = _vscprintf(fmt, marker) + 1;    //獲取格式化字符串長度
            std::vector<char> vBuffer(nLength, '\0');        //創建用于存儲格式化字符串的字符數組
            int nWritten = _vsnprintf_s(&vBuffer[0], vBuffer.size(), nLength, fmt, marker);
            
if (nWritten>0)
            {
                strResult 
= &vBuffer[0];
            }            
            va_end(marker);                                    
//重置變量參數
        }
        
return strResult; 
    }
    
//字符串格式化函數
    std::wstring format(const wchar_t *fmt, 
    { 
        std::wstring strResult
=L"";
        
if (NULL != fmt)
        {
            va_list marker 
= NULL;            
            va_start(marker, fmt);                            
//初始化變量參數
            size_t nLength = _vscwprintf(fmt, marker) + 1;    //獲取格式化字符串長度
            std::vector<wchar_t> vBuffer(nLength, L'\0');    //創建用于存儲格式化字符串的字符數組
            int nWritten = _vsnwprintf_s(&vBuffer[0], vBuffer.size(), nLength, fmt, marker); 
            
if (nWritten > 0)
            {
                strResult 
= &vBuffer[0];
            }
            va_end(marker);                                    
//重置變量參數
        }
        
return strResult; 
    } 
}
#endif
測試全碼(其中str.hpp就是上面代碼的文件名了):
#include <iostream>
#include 
<cassert>
#include 
"str.hpp"
int main(int argc, char* argv[])
{
    
const double PI=3.1415926;
    std::
string s=str::format("ANSI%s---字符:%c;整數:%d;雙精度:%f""測試",'a'38, PI);
    std::cout
<<s<<std::endl;

    std::wstring ws
=str::format(L"UNICODE%s---字符:%c;整數:%d;雙精度:%f", L"測試",'u'83, PI);
    std::wcout
<<ws<<std::endl;

    system(
"pause");
    
return 0;
}
輸出結果:

   問題一:前面的format函數只能在vs2005下通過編譯,在vc6.0下就不可以,原因是用于“獲取格式化字符串長度”的_vscprintf和_vscwprintf在vc6.0中找不到替代品;
   問題二:相信大家已經看到了,ANSI字符串的測試沒有任何問題,但UNICODE字符串在輸出時中斷了,確切的說是在輸出到中文時中斷了,我用斷點查看過,ws的構造沒有問題,即wchar_t版的format函數沒有問題,那么問題就應該出在std::wcout上面,但問題在哪呢?
   諸位看官,歡迎提供任何指導意見。







李現民 2008-09-02 10:23 發表評論
]]>
色婷婷综合久久久中文字幕| 91精品国产高清久久久久久国产嫩草 | 无码人妻久久一区二区三区 | 国产午夜久久影院| 一本一道久久综合狠狠老| 女同久久| 热久久最新网站获取| 色偷偷91久久综合噜噜噜噜| 久久99精品久久久久久野外| 国产成人精品久久一区二区三区av | 亚洲国产精品无码久久青草| 欧洲国产伦久久久久久久| 久久综合狠狠综合久久97色| 久久久久久亚洲精品无码| 亚洲欧美日韩精品久久亚洲区 | 99热成人精品免费久久| 久久综合久久久| 久久精品亚洲欧美日韩久久| 手机看片久久高清国产日韩| 国产精品乱码久久久久久软件| 亚洲国产精品久久电影欧美| 久久精品亚洲精品国产色婷| 99久久精品免费观看国产| 国产亚洲色婷婷久久99精品91| 久久综合色之久久综合| 伊人久久大香线蕉av不变影院| 久久精品国产亚洲网站| 亚洲精品无码久久久久AV麻豆| 久久丫精品国产亚洲av| 国产成人精品久久综合| 久久精品国产清自在天天线| 国产精品久久久福利| 一本一本久久a久久精品综合麻豆| 亚洲国产精品无码久久久蜜芽| 国产精品久久网| 色妞色综合久久夜夜| 久久精品免费观看| 亚洲欧洲日产国码无码久久99| 久久久国产精品福利免费| 久久高清一级毛片| AV狠狠色丁香婷婷综合久久|