??xml version="1.0" encoding="utf-8" standalone="yes"?>99久久精品国产一区二区三区,亚洲AV无码久久寂寞少妇,丁香色欲久久久久久综合网http://www.shnenglu.com/zqsand/category/12249.html啥是子标?/description>zh-cnFri, 22 Jan 2010 12:27:00 GMTFri, 22 Jan 2010 12:27:00 GMT60More Effective C++ (1)http://www.shnenglu.com/zqsand/archive/2010/01/18/105931.htmlrikisandrikisandMon, 18 Jan 2010 06:16:00 GMThttp://www.shnenglu.com/zqsand/archive/2010/01/18/105931.htmlhttp://www.shnenglu.com/zqsand/comments/105931.htmlhttp://www.shnenglu.com/zqsand/archive/2010/01/18/105931.html#Feedback0http://www.shnenglu.com/zqsand/comments/commentRss/105931.htmlhttp://www.shnenglu.com/zqsand/services/trackbacks/105931.htmlW四?nbsp; 效率

······条款16 C80-20准则

大约20%的代码用了80%的资源,E序的整体性能是由该程序的一部分代码所军_的~

可行的办法是使用E序分析器(profilerQ来扑ֈD性能瓉的拿20%的程序~

而且要针寚w成瓉的资源来使用相应的分析器~

 

······条款17  考虑使用延迟计算

延迟计算Q?也就是说知道E序要求l出l果的时候才q行q算~ 很好理解Q和操作pȝ中的cow copy on write 一个原理~

四个使用场景Q?/font>

~1~ 引用计数 Q?/font>

  class String{…};

String s1 = “hello”;

String s2 = s1 ;      //call string Copy ctor

通常情况下,s2赋值后会有一个hello的拷贝,者通常需要用new操作W分配内存,之后strcpys1

的数据给他,但如果下面的操作如下的话Q?/font>

cout << s1 ;

cout << s1 + s2;

q种情况下如果只增加s1的引用计敎ͼ而s2只是׃ns1的值就可以了。只有在需要对s2q行修改或者s1q行修改Ӟ才需要真正拷贝给s2一个副本,引用计数的实现在29条款

~2~区分d操作

如: String s = “homer’s all”;

cout<< s[3];

s[3] = ‘x’;

在进行读操作Ӟ使用引用计数是开销很小的,然而写操作必须生成新的拯。通过条款30的代理类我们可以把判断读写操作推q到我们能够军_哪个是正操作的时?/font>

~3~延迟d

假设E序使用了包含许多数据成员的大对象,q些对象必须在每ơ程序运行的时候保留下来,因此存进了数据库。某些时候从database中取出所有数据是没有必要的,比如他只讉K该对象中的一个数据成员。此Ӟ应该对对象进行处理,只有对象内部某一个特定的数据成员被访问的时候才把他取出来。类gos中的按需换页~

class LargeObject{

    LargeObject(ObjectID id);

const string& field1() const;

int field2() const;

double field3() const;

const string& field4() const;

private:

ObjectID id;

mutable string* field1value;

mutable int   * fieldValue;

};

LargeObject::LargeObject(ObjectID id):oid(id),fieldValue(0),…{}

const string& LargeObject::field1()const{

   if(fieldValue == 0){

       //read the data for field 1 from database and make field1 point to it

   }

   return  *field1Value;

}

实施lazy fetching M成员函数都需要初始化I指针以指向有效数据。但是const成员函数中,试图修改数据~译器会报错。所以声明字D|针ؓ mutable Q表CZQ何函数都可以修改,即便在const成员函数中也可以~ 条款28中的指针可以让这一Ҏ更灵z?/font>

~3~延迟表达式求?/font>

数D领域,也在使用延迟计算。例?/font>

matrix<int> m1(1000,1000);

matrix<int> m2(1000,1000);

matrix<int> m3 = m1 + m2;

如果此时计算出m3的话q算量非怹大~

但是如果此时E序为:

m3 = m4*m1;

那么刚才的计就没必要了

如果cout<< m3[4];

我们只需要计m3[4]可以了Q其他的值等到确实需要他们的时候才予以计算~如果q气够好的话永远不需要计~

ȝQgq计只有当软g在某U程度下可以被避免时候才有意义~只有延迟计算得到的好处大于设计它与实现它p的精力时才有意义~

·······条款18Q?分期摊还预期的计开销

提前计算~ over-eager evaluation 在系l要求你做某些事情之前就做了他~

例如Q大量数据的集合

template<class NumericalType>

class DataCollection}{

public:

  NumericalType min() const;

  NumericalType max() const;

  NumericalType avg() const;

};

使用提前计算Q我们随时跟t目前集合的最大最^均|q样 min max avg被调用时候,我们可以不用计算立刻q回正确的数值~~

提前计算的思想便是Q如果预计某个计会被频J调用,你可以通过设计你的数据l构以更高效的办法处理请求,q样可以降低每次h的^均开销~

最单的做法?~存已经计算qƈ且很可能不需要重新计的那些值~

例如在数据库中存有很多办公室的电话号码,E序在每ơ查询电话时先查询本地的~存如果没找到再去访问数据库Qƈ且更新缓存,q样使用~存q_讉K旉要大大减?/font>

预处理也是一U策略?/font>

例如设计动态数l的时候,当烦引下标大于已有最大范围时候,需要new出新的空_如果甌两倍于索引的大的话就可以避免频繁的申h作~~~

 

········条款 19 Q?了解临时对象的来?/font>

如果一个对象被创徏Q不是在堆上Q没有名字,那么q个对象是临时对象?/font>

通常产生于: Z使函数调用能够成功而进行的隐式转换Q或者函数返回对象是q行的隐式{换。由于构造和析构他们带来的开销可以l你的程序带来显著的影响Q因此有必要了解他们~

~1首先考虑Z函数调用能通过产生的时对象的情况

传给某个函数的对象的cd和这个函数所l定的参数类型不一致的情况下会出现q种情况?/font>

例如Q?/font>

size_t count(const string& str,char ch);

函数定义str中ch的数?/font>

char buffer[100];

cout<<count(buffer,‘c’);

传入的是一个char数组Q此时编译器会调用str的构造函敎ͼ利用buffer来创Z个时对象?/font>

在调用完countChar语句后这个时对象就被自动销毁了~

仅当传值或者const引用的时候才会发生这Lcd转换~当传递一个非帔R引用的时候,不会发生?/font>

void uppercasify(string& str); //change all chars in str to upper case;

在这个例子中使用char数组׃会成功~

因ؓE序作者声明非帔R引用也就是想让对引用的修改反映在他引用的对象w上Q但是如果此时生成了临时对象Q那么这些修改只是作用在临时对象w上Q也׃是作者的本意了。所以c++止非常量引用生时对象?/font>

~2 函数q回对象时候会产生临时对象

例如Q?const Number operator + ( const Number& lhs,const Number& rhs);

q个函数q回一个时对象,因ؓ他没有名字,只是函数的返回倹{?/font>

条款20?Q会介绍让编译器对已l超出生存周期的临时对象q行优化

 

········条款20Q?协助~译器实现返回g?/font>

q回g化:q回带有参数的构造函数?/font>

cosnt Rational operator * (cosnt Rational& lhs,const Rational& rhs){

    return Rational(lhs.numerator()*rhs.numerator(),lhs.denomiator()*rhs.denominator()};

c++允许~译器针对超出生命周期的临时对象q行优化。因此如果调用Rational c=a*bQ?/font>

c++允许~译器消除operator*内部的时变量以及operator*q回的时变量,~译器可以把return表达式所定义的返回对象构造在分配lc的内存上。如果这样做的话那么调用operator*所产生的时对象所带来的开销是0~ 我们可以把operator 声明为内联函数而去除调用构造函数带来的开销~

#include <iostream>
#include <string>
#include "time.h"
using namespace std;
char buffer[100];
class number{
public:
    const friend  number operator * (const number& rhs,const number lhs);
    number(){}
    number(int b):a(b){}
    number(const number& rhs){
        a = rhs.a;
    }
      int a;
};
const number operator*(const number& rhs,const number lhs){
    number res;
    res.a = rhs.a * lhs.a;
        return res;
    /*return number(rhs.a*lhs.a);*/
}
//CLOCKS_PER_SEC
int main()
{
    clock_t start = clock();
    number A(5);number B(6);
    for(int i=0;i<100000000;i++)
        number C = A*B;

    clock_t end = clock();
    cout<<double(end-start)/CLOCKS_PER_SEC<<endl;
}

通过上面的程序运?如果没有q回g?q行旉 15.9s 优化后是 10.1s

q是很显著的?快了33% Q如果这U情况出现在E序的热点处~效果很好了

 

·········条款21 Q?通过函数重蝲避免隐式cd转换

例子Q?/font>

class upint{

public:

upint();

upint(int value);

};

cosnt upint operator+(const upint&lhs,const upint&rhs);

upint up1,up2;

upint up3 = up1+up2;

upi3 = up1 +10;

upi4 = 10+ upi2;

q些语句也可以通过Q因为创Z临时对象Q通过带有int的构造函C生了临时的upint对象Q如果我们不愿意些时对象的产生与析构付ZP我们需要做什么:

我们声明 cosnt upint operator+(cosnt upint&lhs,int rhs);

cosnt upint operator+(int lhs,const upint& rhs);

可以去除时对象生了~

但是如果我们写了 const upint operator+(int lhs,int rhs); // 错了~

c++规定Q每一个被重蝲的运符必须臛_有一个参数属于用戯定义cdQintq不是自定义cd所以上面的不对?/font>

同样的如果希望string char* 作ؓ参数的函敎ͼ都有理由q行重蝲而避免隐形类型{换(仅仅在有必要的时候,也就是说他们可以对程序效率v到很大帮助的时候~Q?/font>

··········条款Q?考虑使用 op = 来取?单独?opq算W?/font>

class Rational{

public:

   Rational& operator+=(const Rational& rhs);

   Rational& operator-=(const Rational& rhs);

}

const Rational operator+(cosnt Rational& lhs,const Rational & rhs){

    return Rational(lhs)+=rhs;

}

利用+= -=来实? -可以保证q算W的赋值Ş式与单独使用q算W之间存在正常的关系?/font>

Rational a,b,c,d,result;

result = a+ b+c+d; // 可能要用?个时对?/font>

result +=a;result+=b;result+=c; //没有临时对象

前者书写维护都更容易,而且一般来说效率不存在问题Q但是特D情况下后者效率更高更可取

注意Q?/font>

如果+的实现是q样的:

const T operator+ (constT& lhs,const T&rhs){

     T result(lhs);

     return result += rhs;

}

q个模版中包含有名字对象resultQ这个对象有名字意味着q回g化不可用~~~~~~~~·

 

·······条款23 Q?考虑使用其他{h的程序库

LQ?/font>

提供cM功能的程序库通常在性能问题上采取不同的权衡措施Q比如iostream和stdioQ所以通过分析E序扑ֈ软g瓉之后Q可以考虑是否通过替换E序库来消除瓉~~~~

 

 

······条款24 : 理解虚函敎ͼ多重l承Q虚基类以及 RTTI 带来的开销

虚函数表Qvtabs 指向虚函数表的指?vptrs

E序中每个声明了或者承了的虚函数的类都具有自q虚函数表。表中的各个就是指向虚函数具体实现的指针?/font>

class c1{

   c1();

   virtual ~c1();

   virtual void f1();

   virtual int f2(char c)const;

   virtual void f3(const string& s);

};

c1 的虚函数表包括: c1::~c1 c1::f1 c1::f2 c1::f3

class c2:public c1{

   c2();

   virtual ~c2();

   virtual void f1();

   virtual void f5(char *str);

};

它的虚函数表入口指向的是那些由c1声明但是c2没有重定义的虚函数指针:

c2::~c2  c2::f1 c1::f2 c1::f3 c2::f5

所以开销上: 必须为包含虚函数的类腑և额外的空间来存放虚函数表。一个类的虚函数表的大小取决于它的虚函数的个敎ͼ虽然每一个类只要有一个虚函数表,但是如果有很多类或者每个类h很多个虚函数Q虚函数表也会占据很大的I间Q这也是mfc没有采用虚函数实现消息机制的一个原因?/font>

׃每一个类只需要一个vtbl的拷贝,把它攑֜哪里是一个问题:

一U:为每一个需要vtbl的目标文件生成拷贝,然后q接时取出重复拷?/font>

或者:更常见的是采用试探性算法决定哪一个目标文件应该包含类的vtbl。试探:一个类的vtbl通常产生在包含该cȝ一个非内联Q非U虚函数定义的目标文仉。所以上面c1cȝvtbl放在c1::~c1 定义的目标文仉。如果所有虚函数都声明ؓ内联Q试探性算法就会失败,在每一个目标文件就会有vtbl。所以一般忽略虚函数的inline指o?/font>

如果一个类h虚函敎ͼ那么q个cȝ每一个对象都会具有指向这个虚函数表的指针Q这是一个隐藏数据成员vptr~被编译器加在某一个位|?/font>

此处W二个开销Q你必须在每一个对象中存放一个额外的指针~

如果对象很小q个开销十分显著~~因ؓ比例大~

此时 void makeCall(c1* pc1){

   pc1->f1();

}

译?(*pc1->vptr[i])(pc1);

Ҏvptr扑ֈvtbl q很单,

在vtbl扑ֈ调用函数对应的函数指针,q个步骤也很单,因ؓ~译器ؓ虚函数表里的每一个函数设|了唯一的烦?/font>

然后调用指针所指向的函数~

q样看来Q调用虚函数与普通函数调用的效率相差无几Q只多出几个指o?/font>

虚函数真正的开销与内联函数有关~Q在实际应用中,虚函C应该被内联,因ؓ内联意味着在编译时ȝ被调用函数的函数体来代替被调用函数。但是虚函数意味着q行时刻军_调用哪个一函数Qso~~~虚函C出的W三个代价啊Q~不能内联Q通过对象调用虚函数的时候,q些虚函数可以内联,但是大多数虚函数通过指针或者以用来调用的)?/font>

~多重l承的情?/font>

多重l承一般要求虚基类。没有虚基类Q如果一个派生类h多个通向基类的承\径,基类的数据成员会被复制到每一个承类对象里,l承cM基类间的每一条\径都有一个拷贝?/font>

有了虚基c,通常使用指向虚基cȝ指针作ؓ避免重复的手D,q样需要在对象内部嵌入一个或者多个指针~也带来了一定的开销~

例如菱Şl承 Q?

class A{};

class B:virtual public A{};

class C:virtual public A{};

class D:public B,public C{};

q里A是一个虚基类Q因为B和C虚拟l承了他?/font>

对象 D 的布局Q?/font>

B data

vptr

pointer to virtual base class

C data

vptr

pointer to virtual base class

D data members

A data members

vptr

上面四个c,只有三个vptrQ因为B和D可以׃n一个vptr  Qؓ啥?Q?/font>

现在我们已经看到虚函数如何对象变得更大Q以及ؓ何不能把它内联了~

下面我们看看RTTI的开销 runtime type identifycation 所需要的开销

通过rtti我们可以知道对象和类的有关信息,所以肯定在某个地方存储了这些供我们查询的信息,q些信息被存储在type_info cd的对象里Q你可以通过typeidq算W访问一个类的type_info对象?/font>

每个cM仅需要一个RTTI的拷贝,规范上只保证提供哪些臛_有一个虚函数的对象的准确的动态类型信息~

whyQ和虚函数有啥关p~ 因ؓrtti设计在vtbl?/font>

vtbl的下?包含指向type_info对象的指针。所以用这U实现方法,消费的空间是vtbl中占用一个额外的单元再加上存储type_info对象所需要的I间?/font>

 

------------------------|恶的结束线 OVER~------------------------------------------



rikisand 2010-01-18 14:16 发表评论
]]>
断言的?/title><link>http://www.shnenglu.com/zqsand/archive/2010/01/17/105886.html</link><dc:creator>rikisand</dc:creator><author>rikisand</author><pubDate>Sun, 17 Jan 2010 11:36:00 GMT</pubDate><guid>http://www.shnenglu.com/zqsand/archive/2010/01/17/105886.html</guid><wfw:comment>http://www.shnenglu.com/zqsand/comments/105886.html</wfw:comment><comments>http://www.shnenglu.com/zqsand/archive/2010/01/17/105886.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zqsand/comments/commentRss/105886.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zqsand/services/trackbacks/105886.html</trackback:ping><description><![CDATA[ <p>解决目的问题,意识到断a的重要性。如果一个程序在某处遇到了非法的|那么最好的情况便是在此d下报错,最坏的情况便是E序不吭不响的执行着~~直到你发C执行的方式极异,此时Q你要花九牛二虎之力才能扑ֈ错误所在之处~~~~</p> <p>学习一下断a吧:</p> <p><font size="3"><font face="YaHei Consolas Hybrid" color="#008000">·······什么是断言</font></font></p> <p><font face="YaHei Consolas Hybrid" color="#008000" size="3">在某处判断某一个表辑ּ的gؓ真或者假Q如果假则输出错误消息ƈ停止E序的执行~</font></p> <p><font face="YaHei Consolas Hybrid" color="#008000" size="3">assert是宏Q而不是函敎ͼ只在debug版本中有效,因此无需在release版本删除?/font></p> <p><font face="YaHei Consolas Hybrid" color="#008000" size="3">·······哪几U断a</font></p> <p><font face="YaHei Consolas Hybrid" color="#008000" size="3">MFC </font></p> <p><font face="YaHei Consolas Hybrid" color="#008000" size="3">ASSERT</font></p> <p>void foo(char* p,int size)<br>{<br>ASSERT(p != 0); // 验证~冲区指?br>ASSERT((size >= 100); // 认~冲区大至ؓ100字节<br>// foo 函数的其它计过E?br>}<br>如果没有定义_DEBUG预处理符Q则该语句不会真正生成代码。Visual C++会在调试模式~译时自动定义_DEBUGQ而在发行模式下,该预处理W是不存在的。如果定义了_DEBUGQ则上述两个断言生成的代码类如: <br>//ASSERT(p != 0);<br>do<br>{<br>if(!(p != 0) && AfxAssertFailedLine(__FILE__, __LINE__))<br>AfxDebugBreak();<br>} while(0);<br>//ASSERT((size >= 100);<br>do<br>{<br>if(!(size >= 100) && AfxAssertFailedLine(__FILE__,__LINE__))<br>AfxDebugBreak();<br>}while(0); </p><p><font face="YaHei Consolas Hybrid" color="#008080" size="3">ASSERT_KINDOF(classname,pObject); ASSERT_KINDOF(CDocument,pDocument);</font></p> <p><font face="YaHei Consolas Hybrid" color="#008080" size="3">验pObject指向的对象是classnamecȝ一个对象或者其zcȝ对象</font></p> <p><font face="YaHei Consolas Hybrid" color="#008080" size="3">ASSERT_VALID(pObject); pObject 必须是一个派生于CObjectcȝcd象,会调用其重写的AssertValid函数 Q例?/font></p> <p>如果使用应用向导或类向导生成ZMFC的类Q通常会得到AssertValid()的骨Ӟ最好改写这些骨架代码以增加最基本的完整性检查。下面是一个典型的例子Q类Sample从CObjectl承Q假定它含有职员名字及其薪水Q?<br>class Sample : public CObject<br>{<br>    protected:<br>    CString m_Name; // 职员名字<br>    double m_Salary; // 薪水<br>public:<br>    Sample(LPCTSTR name,double salary) : m_Name(name), m_Salary(salary) {}<br><em>   #ifdef _DEBUG<br>        virtual void AssertValid() const;<br>    #endif</em><br>};<br><em>#ifdef _DEBUG<br>void Sample::AssertValid() const<br>{<br>    CObject::AssertValid(); // 验证基类<br>    ASSERT(!m_Name.IsEmpty()); // 验证职员名字<br>    ASSERT(m_Salary > 0); // 验证薪水<br>}<br>#endif</em> </p><p><font face="YaHei Consolas Hybrid" color="#408080" size="3">CRT assertion</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">_ASSERT ?nbsp; _ASSERTE 后一个会在出错时同时打印出条件判断句</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">ANSI</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">assert()</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">注意Qassert用于非法的输入Q但是合法的输入q不一定是正确的,例如Q?/font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">int pB = (int*)malloc(sizeof(int)*1000);</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">assert(pB!=NULL) //错误的用assert 他会在release版本失效~也就是说assert不应该对E序产生副作?/font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">正确的做法:</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">int pB = (int*) malloc(sizeof(int)*1000);</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">if(pB == NULL)</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">{<br>   //错误处理</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">else{</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">另一个例子:</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">void draw(){</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">   CFigure* pF = getCF();</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">   assert(pf!=NULL);</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">   if(pf == NULL){}</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">   else{</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">   }</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">}</font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">此处Q对于getCF来说q回gؓNULL是非法的Q如果他的返回值可能ؓnull没必要加上assert语句?/font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">而下面的if语句则是Z防止release版本出现null指针的情c?</font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#408080"> </font></p> <p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#408080"> </font></p> <p><font face="YaHei Consolas Hybrid" color="#408080" size="3">VERIFY()</font></p> <p><font color="#408080">׃ASSERT仅在E序的调试版起作用,试表达式L被动的。也是_它们不能包含赋倹{增量、减量等真正改变数据的操作。但有时候我们需要验证一个主动表辑ּQ比如赋D句。这时可以用VERIFY代替ASSERT。下面是一个例子: <br>void foo(char* p,int size)<br>{<br>char* q; // 指针的副?br><em>VERIFY(q = p);</em> // 拯指针q执行验?br>ASSERT((size >= 100); // 保~冲区大至ؓ100字节<br>// 执行 foo 的其它操?br>}<br>在调试模式下ASSERT和VERIFY是相同的。但在release模式下,VERIFY能够l箋对表辑ּ求|但不再进行断a验)Q而ASSERT语句在效果上如同已l删除了一栗?<br>管在MFC源代码中可以扑ֈ一些应用VERIFY的例子,但ASSERT用得更ؓ普遍。一些程序员L完全避免使用VERIFYQ因Z们已l习惯于使用被动断言。请CQ如果在ASSERT语句中用了d表达式,~译器不会发ZQ何警告。在发行模式下编译时该表辑ּ会被直接删除Q从而导致程序运行的错误。由于发行版E序不含调试信息Q这U类型的错误是很难找到原因的?</font> </p><p><font face="YaHei Consolas Hybrid" size="3"></font><font color="#408080"> </font></p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font> </p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font> </p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font> </p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font> </p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font> </p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font> </p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font> </p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font> </p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font> </p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font> </p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font> </p> <p><font face="YaHei Consolas Hybrid" color="#004080" size="3"></font></p><img src ="http://www.shnenglu.com/zqsand/aggbug/105886.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zqsand/" target="_blank">rikisand</a> 2010-01-17 19:36 <a href="http://www.shnenglu.com/zqsand/archive/2010/01/17/105886.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++ RTTI (1)http://www.shnenglu.com/zqsand/archive/2010/01/03/104714.htmlrikisandrikisandSun, 03 Jan 2010 09:59:00 GMThttp://www.shnenglu.com/zqsand/archive/2010/01/03/104714.htmlhttp://www.shnenglu.com/zqsand/comments/104714.htmlhttp://www.shnenglu.com/zqsand/archive/2010/01/03/104714.html#Feedback0http://www.shnenglu.com/zqsand/comments/commentRss/104714.htmlhttp://www.shnenglu.com/zqsand/services/trackbacks/104714.html目中遇C RTTI 先学一部分 c++ primer内容

  1. q行时类型识别:

E序可以使用基类的指?/font>或者引用来索这些指针或引用所指对象的实际zcd

标准库提供了两个操作W:

1. typeid    他可以返回指针或者引用所指向对象的实际类?/font>

2. dynamic_cast  基cȝ型的指针或引用安全的转ؓzcȝ指针或者引?nbsp;                           

对于不带虚函数的cd~译时期执行Q否则在q行期间执行

使用时机Q?/font>

基类指针调用zcL员函数的话,一般应使用虚函敎ͼq样~译器会Ҏ对象的实际类型来选择正确的函数。但是某些情况下无法使用虚函敎ͼ那么?/font>

时如果需要用基cL针调用派生类成员函数侉K要用RTTI强制转换Q而且必须查{换是否成?/font>?/font>

(一) Dynamic_cast

dynamic_cast 如果转换到指针失败则q回 0 如果转换到引用类型失败则抛出 bad_cast 异常

Ҏ针操作:

if(Derived *derivedPtr = dynamic_cast<Derived*> (basePtr)){

    //basePtr point to a derived object;

}else{

   //basePtr point to a base object;

}

?if 语句中进行检?1.条g代码内部知道 derivedPtr 的类?2.不可能在试代码和用代码中加入代码Q也是说不会在没有试前就使用derivedPtr 3.如果p|外部不会使用未绑定的指针derivedPtr

对引用操作:

因ؓ不存在空引用所以{换失败抛出异?/font>

void f(const Base& b){

    try{

        const Derived &d = dynamic_cast<const Derived&> (b);

    }catch(bad_cast){

    }

}

(? typeid

typeid(e) e是Q意的表达式或者类型名

Base *bp;

Derived *dp;

//compare type at run time of two objects

if(typeid(*bp)==typeid(*dp)){

    //bp dp point to objects of the same type

}

if(typeid(*bp)==typeid(Derived)){

    //bp actually point to a Derived

}

注意typeid 试的是 *bp 对象

//test always fails: The type of bp if pointer to Base

if(typeid(bp)==typeid(Derived)){

}

Base* 永q和Derivedcd不同

只有typeid 的操作数是带虚函数的cȝ对象的时候,才返回动态类型信息,试指针q回指针的静态的Q编译时cd

Q三 Qtype_info c?/p>

作ؓtypeid的返回?提供

t1==t2 t1!=t2 t.name() 的操?/p>

 

作ؓ应用例子Q可以实C个类型敏感的相等操作W?/p>

friend bool operator == (const base& lhs, const base& rhs){

    return typeid(lhs)==typeid(rhs) && lhs.equal(rhs);

}

q样可以处理基类子类混合的相{判断了



rikisand 2010-01-03 17:59 发表评论
]]>
State 模式http://www.shnenglu.com/zqsand/archive/2009/12/29/104405.htmlrikisandrikisandTue, 29 Dec 2009 13:25:00 GMThttp://www.shnenglu.com/zqsand/archive/2009/12/29/104405.htmlhttp://www.shnenglu.com/zqsand/comments/104405.htmlhttp://www.shnenglu.com/zqsand/archive/2009/12/29/104405.html#Feedback0http://www.shnenglu.com/zqsand/comments/commentRss/104405.htmlhttp://www.shnenglu.com/zqsand/services/trackbacks/104405.htmlSTATE 模式Q?/font>

一个对象的行ؓ取决于他的状态,而且它必dq行时根据状态改变他的行为。常规实CQ一个操作含有庞大的多分支的条g语句Q且q些分支依赖于该对象的状态。这个状态通常使用一个或者多个枚丑ָ量表C。STate模式把这些状态时候的对象看做一个独立的对象Q也是不同状态时的行为分散到相应的状态类中。要辑ֈq样的效果,需要contextQ也是状态的持有者,卛_先的c;抽象状态类Q他装了与context交互的接口;具体状态类Q也是一个个的具体状态。context中保存一个抽象状态类对象为成员,qdelegate对象行ؓl他Q从而相应状态下的行Z码生效。如果状态改变的准则不是固定的则state状态类同时应该重写changestatecM控制状态的改变Q否则可以在context中实现?/font>

具体到我们的目Q?/font>

每一个device即ؓcontextQ他拥有一个state对象Qdevice中的函数processMsg(){state->processMSg();} ׃状态改变的规则依赖于收到的消息Q也是说一个状态可能{换到多个状态device的每个状态需要重写statechangeҎQstateChange(){state->stateChange(thisQmsg);} q样Q不同的状态下的行为实现在具体状态的cMQ比原先的版本清晰明了,可读性更强?/font>



rikisand 2009-12-29 21:25 发表评论
]]>
ALGORITHM IN C (1)http://www.shnenglu.com/zqsand/archive/2009/11/11/100725.htmlrikisandrikisandWed, 11 Nov 2009 12:18:00 GMThttp://www.shnenglu.com/zqsand/archive/2009/11/11/100725.htmlhttp://www.shnenglu.com/zqsand/comments/100725.htmlhttp://www.shnenglu.com/zqsand/archive/2009/11/11/100725.html#Feedback0http://www.shnenglu.com/zqsand/comments/commentRss/100725.htmlhttp://www.shnenglu.com/zqsand/services/trackbacks/100725.htmlSteps to developing a usable algorithm.
• Define the problem.
• Find an algorithm to solve it.
• Fast enough?
• If not, figure out why.
• Find a way to address the problem.
• Iterate until satisfied.

 

主要内容 FIND-UNION ALGORITHM

是利用q查集来考察q通性的法 。条件N个节点,M对节点,输入每一对节Ҏ候,如果已经q通,则忽略,否则输出接点q更?

主要介绍三种法Q第一U,QUCK-FIND 利用数组记录每一个联通子图,同一个联通子囄节点数组变量是相同的。因此每d一对就需要遍历N个数l变量考察是否需要更斎ͼ最坏时间MNQ实际上每个子图为高度ؓ2的树;W二U,QUICK-UNION 联通子N要union?仅仅需要将两个root union 因此每个联通子N度变高,所有find root 会消耗一定时_当然无需遍历N?Q最坏时_也就是每ơ均需要从叶子节点d溯求根(q里书中丑־例子好像有问题)也是MNQ第三种也就?QUICK WEIGHT UNION q种Ҏ在两个子树合q的时候,不是单的指定合ƈ{略Q而是l过判断的,把size(相应高度也小Q的合ƈ到size大的里面Q实际上很容易理解就是尽量减树的高度来q求quick-find的效率;

q而作者写道\径压~,也是q种思想。或者实Cؓ全部压羃Q也是说在q行union操作的时候,所有check的节炚w直接链接到union后的新root下面Q或者half union Q容易实C性能好)每次check时候,如果没有停止loop单的?id[i]=id[id[i]];卛_辑ֈ减少到根距离的效果?

half union 的主要代码:

int i,j;
for(i=p;id[i]!=i;i=id[i]) id[i]=id[id[i]];
for(j=p;id[j]!=j;j=id[j]) id[j]=id[id[j]];
if(i==j)continue;
if(size[i]>size[j]) id[j]=i,size[i]+=size[j];
else        id[i]=j,size[j]+=size[i];

 

W一ơ用windows live writer 试试效果哦~~

 

 

 

 

 

 

 

 



rikisand 2009-11-11 20:18 发表评论
]]>
11.7http://www.shnenglu.com/zqsand/archive/2009/11/07/100354.htmlrikisandrikisandSat, 07 Nov 2009 13:18:00 GMThttp://www.shnenglu.com/zqsand/archive/2009/11/07/100354.htmlhttp://www.shnenglu.com/zqsand/comments/100354.htmlhttp://www.shnenglu.com/zqsand/archive/2009/11/07/100354.html#Feedback0http://www.shnenglu.com/zqsand/comments/commentRss/100354.htmlhttp://www.shnenglu.com/zqsand/services/trackbacks/100354.html
what's this
and ...
?Q做完了p写下?省的之后忘了
昨天看的misof的教E?关于数~ 今天做了其中的提到的例题Q?/div>
BorelSe:
simple的题~W一ơ没搞对Q搞完后发现q是写麻烦了。题目中明确说明Q也显而易见的是空集和全集一定是B集里?Q我q费心去处理I集。。?/div>
其次Q重复的数字不用处理Q因为用的是或操作?/div>
剩下的就是用一个数l和一个set不断循环了,其实用队列效果很好的Q恩···

 1         int howMany(int size, vector <string> sub)
 2         {
 3                  set<int> q;q.clear();string str;
 4                  int mask=(1<<size)-1;
 5                  VI C;
 6                  REPV(sub,i){
 7                      if(sub[i]=="")C.push_back(0),q.insert(0);
 8                      else{
 9                       set<int> vec;
10                       stringstream ss(sub[i]);str="";
11                       while(ss>>str) {
12                                     if(str=="")vec.insert(0);
13                                     else vec.insert(atoi(str.c_str())-1); 
14                                     } 
15                      
16                     int now=0;
17                     for(set<int>::iterator it=vec.begin();it!=vec.end();it++){
18                         now|=(1<<(*it));
19                     }
20                     if(q.count(now)==0) C.push_back(now),q.insert(now);
21                     } 
22                 }
23                 int last=q.size();
24                 while(true){
25                     REPV(C,i) 
26                     {
27                         int s=C[i]^mask;if(q.count(s)==0)C.push_back(s),q.insert(s);
28                         REP(j,i)
29                         {
30                         int k= C[i]|C[j];
31                         if(q.count(k)==0)C.push_back(k),q.insert(k);
32                         }
33                     }
34                     if(last==q.size())return last;
35                     else last=q.size();
36                 }
37         }
关于数字Q?/div>
2的nơ方 换算?10的次?大概?n/3 数量U的 也就是说 ?n/3+1 大小可以了
q个是double 的数?/div>
 signexponentmantissa
single precision1823
double precision11152

     


rikisand 2009-11-07 21:18 发表评论
]]>Hello Blog World~~ http://www.shnenglu.com/zqsand/archive/2009/11/07/100348.htmlrikisandrikisandSat, 07 Nov 2009 11:27:00 GMThttp://www.shnenglu.com/zqsand/archive/2009/11/07/100348.htmlhttp://www.shnenglu.com/zqsand/comments/100348.htmlhttp://www.shnenglu.com/zqsand/archive/2009/11/07/100348.html#Feedback0http://www.shnenglu.com/zqsand/comments/commentRss/100348.htmlhttp://www.shnenglu.com/zqsand/services/trackbacks/100348.html呵呵~~ just test

#include<iostream>
using namespace std;
int main()
{
   cout
<<"hello world~"<<endl;
   
return 0;
}


rikisand 2009-11-07 19:27 发表评论
]]> 97þùۺϾƷŮ| þۺϺݺۺϾþ97ɫ| þ޴ɫĻþþ| þۺϸþúݺ97ɫ| 99ŷƷþþѿ| ϼþùƷӰԺ| 99þþƷѾƷ | ɫ͵͵88888ŷƷþþ| þӰԺۺϾƷ| þù| þþŮ붯ȺëƬ| ƷþþӰ㽶| ƯޱгĻþ | þ޸ۿ| þù޾Ʒ| ˾Ʒþ޸岻 | þþþþþþ˳| þùƷ-þþƷ| þۺɫˮ99ž| 99þþƷëƬѲ| Ժձһձþ| þþƷ99þ޶| þùһ| ŷһþ| ޾Ʒþþþ66| ޾Ʒ99þþþĻ| 91ƷۺϾþ| ԭƷ99þþƷ66| þˬˬAV| þһŷպ | þþþƷƵѹۿ| þþƷƷƷ| ޾ƷþþӰԺӰƬ | þþþŮ˾ƷëƬ| ޾Ʒþþþþ| vĻþ 뾫ƷþɪӰ | ޾ƷNVþþþþþþþ| þþþ޾Ʒ˵| wwwɫ˾þþƷ| wwwþ| þùҹƷһ|