??xml version="1.0" encoding="utf-8" standalone="yes"?>久久久久中文字幕,久久综合久久综合九色,国产精品久久久久无码avhttp://www.shnenglu.com/tianbianlan/zh-cnWed, 07 May 2025 01:20:41 GMTWed, 07 May 2025 01:20:41 GMT60 Sequoiadb与sparkҎ步骤http://www.shnenglu.com/tianbianlan/archive/2015/05/26/210753.html天边?/dc:creator>天边?/author>Tue, 26 May 2015 09:13:00 GMThttp://www.shnenglu.com/tianbianlan/archive/2015/05/26/210753.htmlhttp://www.shnenglu.com/tianbianlan/comments/210753.htmlhttp://www.shnenglu.com/tianbianlan/archive/2015/05/26/210753.html#Feedback0http://www.shnenglu.com/tianbianlan/comments/commentRss/210753.htmlhttp://www.shnenglu.com/tianbianlan/services/trackbacks/210753.html hive.aux.jars.path file:///ocsdev/hadoop/apache-hive-1.1.0-bin/lib/hive-sequoiadb-apache.jar,file:///ocsdev/hadoop/apache-hive-1.1.0-bin/lib/sequoiadb.jar Sequoiadb store handler jar file 2.配置SPARK_CLASSPATH export SPARK_CLASSPATH=/path/to/spark/lib/sequoiadb-driver-1.12.jar:/path/to/spark/lib/lib/spark-sequoiadb_2.10-1.12.jar:/ocsdev/hadoop/spark-1.3.1-bin-hadoop2.6/lib://path/to/spark/lib/mysql-connector-java-5.1.5-bin.jar 3.sequoiadb-driver-1.12.jar、spark-sequoiadb_2.10-1.12.jar拯到spark的lib目录下; 4.hive-site.xml配置元数据存储方? hive.metastore.local true javax.jdo.option.ConnectionURL jdbc:mysql://192.168.0.103:3306/hive?characterEncoding=UTF-8 javax.jdo.option.ConnectionDriverName com.mysql.jdbc.Driver javax.jdo.option.ConnectionUserName hive javax.jdo.option.ConnectionPassword hive 5.创徏Sequoiadb集合映射关系Q? ./spark_sql >CREATE table lw_test_sdb (id int, r5 double) using com.sequoiadb.spark OPTIONS ( host '192.168.0.103:11810,192.168.0.104:11810,192.168.0.102:11810', collectionspace 'hj', collection 'aws_min',username '',password ''); 6.查询数据 >select * from lw_test_sdb NULL 0.0 23 23.4 12 34.5 Time taken: 0.825 seconds, Fetched 3 row(s)

]]>
RDD初探http://www.shnenglu.com/tianbianlan/archive/2015/04/18/210383.html天边?/dc:creator>天边?/author>Sat, 18 Apr 2015 14:16:00 GMThttp://www.shnenglu.com/tianbianlan/archive/2015/04/18/210383.htmlhttp://www.shnenglu.com/tianbianlan/comments/210383.htmlhttp://www.shnenglu.com/tianbianlan/archive/2015/04/18/210383.html#Feedback0http://www.shnenglu.com/tianbianlan/comments/commentRss/210383.htmlhttp://www.shnenglu.com/tianbianlan/services/trackbacks/210383.html

]]>
[转]The Biggest Changes in C++11 http://www.shnenglu.com/tianbianlan/archive/2013/05/05/199992.html天边?/dc:creator>天边?/author>Sun, 05 May 2013 13:26:00 GMThttp://www.shnenglu.com/tianbianlan/archive/2013/05/05/199992.htmlhttp://www.shnenglu.com/tianbianlan/comments/199992.htmlhttp://www.shnenglu.com/tianbianlan/archive/2013/05/05/199992.html#Feedback0http://www.shnenglu.com/tianbianlan/comments/commentRss/199992.htmlhttp://www.shnenglu.com/tianbianlan/services/trackbacks/199992.html

源文章来自前C++标准委员会的 Danny Kalev ?nbsp;The Biggest Changes in C++11 (and Why You Should Care)Q赖勇浩做了一?a target="_blank">中文译在这?/a>。所以,我就不翻译了Q我在这里仅Ҏ中提到的q些变化“q问Z么要引入q些变化”的一个探讨,只有知道Z什么,用在什么地方,我们才能真正学到q个知识。而以此你可以更深入地了解q些变化。所以,本文不是译。因为写得有些仓促,所以难免有问题Q还请大家指正?/p>

Lambda 表达?/h4>

Lambda表达式来源于函数式编E,说白׃是在用的地方定义函数Q有的语a?#8220;闭包”Q如?lambda 函数没有传回?例如 void )Q其回返cd可被完全忽略?定义在与 lambda 函数相同作用域的变量参考也可以被用。这U的变量集合一般被UC closureQ闭包)。我在这里就不再讲这个事了。表辑ּ的简单语法如下,

1
[capture](parameters)->return_type {body}

原文的作者给Z下面的例子:

1
2
3
4
5
6
7
8
9
10
int main()
{
   char s[]="Hello World!";
   int Uppercase = 0; //modified by the lambda
   for_each(s, s+sizeof(s), [&Uppercase] (char c) {
    if (isupper(c))
     Uppercase++;
    });
 cout << Uppercase << " uppercase letters in: " << s <<endl;
}

在传l的STL中for_each() q个玩意最后那个参数需要一?#8220;函数对象”Q所谓函数对象,其实是一个classQ这个class重蝲了operator()Q于是这个对象可以像函数的式L使用。实C个函数对象ƈ不容易,需要用templateQ比如下面这个例子就是函数对象的单例子(实际的实现远比这个复杂)Q?/p>

1
2
3
4
5
6
7
8
9
template <class T>
class less
{
public:
    bool operator()(const T&l, const T&r)const
    {
        return l < r;
    }
};

所以,C++引入Lambda的最主要原因是1Q可以定义匿名函敎ͼ2Q编译器会把其{成函数对?/strong>。相信你会和我一P会疑问ؓ什么以前STL中的ptr_fun()q个函数对象不能用?Qptr_fun()是把一个自然函数{成函数对象的Q。原因是Qptr_fun() 的局限是其接收的自然函数只能??个参数?/p>

那么Q除了方便外Qؓ什么一定要使用Lambda呢?它比传统的函数或是函数对象有什么好处呢Q我个h所理解的是Q这U函Cq以?#8220;闭包”Q就是因为其限制了别人的讉KQ更U有。也可以认ؓ他是一ơ性的Ҏ。Lambda表达式应该是z的Q极U有的,Z更易的代码和更方便的~程?/p>

自动cd推导 auto

在这一节中Q原文主要介l了两个关键?auto ?deltypeQ示例如下:

1
2
3
4
auto x=0; //x has type int because 0 is int
auto c='a'; //char
auto d=0.5; //double
auto national_debt=14400000000000LL;//long long

auto 最大的好处是让代码简z,其是那些模板类的声明,比如QSTL中的容器的P代子cd?/p>

1
vector<int>::const_iterator ci = vi.begin();

可以变成Q?/p>

1
auto ci = vi.begin();

模板q个Ҏ让C++的代码变得很难读Q不信你可以看看STL的源码,那是一个ؕ啊。用auto必需一个初始化|~译器可以通过q个初始化值推导出cd。因为auto是来化模板类引入的代码难ȝ问题Q如上面的示例,iterationq种cd最适合用auto的,但是Q我们不应该把其滥用?/p>

比如下面的代码的可读性就降低了。因为,我不知道ProcessDataq回什么?int? bool? q是对象Q或是别的什么?q让你后面的E序不知道怎么做?/p>

1
auto obj = ProcessData(someVariables);

但是下面的程序就没有问题Q因为pObject的型别在后面的new中有了?/p>

1
auto pObject = new SomeType<OtherType>::SomeOtherType();

自动化推?decltype

关于 decltype 是一个操作符Q其可以评估括号内表辑ּ的类型,其规则如下:

  1. 如果表达式e是一个变量,那么是q个变量的类型?/li>
  2. 如果表达式e是一个函敎ͼ那么是q个函数q回值的cd?/li>
  3. 如果不符??Q如果e是左|cd为TQ那么decltype(e)是T&Q如果是叛_|则是T?/li>

原文l出的示例如下,我们可以看到Q这个让的确我们的定义变量省了很多事?/p>

1
2
3
const vector<int> vi;
typedef decltype (vi.begin()) CIT;
CIT another_const_iterator;

q有一个适合的用法是用来typedef函数指针Q也会省很多事。比如:

1
2
3
decltype(&myfunc) pfunc = 0;
 
typedef decltype(&A::func1) type;

auto ?decltype 的差别和关系

Wikipedia 上是q么说的Q关于decltype的规则见上)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <vector>
 
int main()
{
    const std::vector<int> v(1);
    auto a = v[0];        // a 的类型是 int
    decltype(v[0]) b = 1; // b 的类型是 const int&, 因ؓ函数的返回类型是
                          // std::vector<int>::operator[](size_type) const
    auto c = 0;           // c 的类型是 int
    auto d = c;           // d 的类型是 int
    decltype(c) e;        // e 的类型是 int, 因ؓ c 的类型是int
    decltype((c)) f = c;  // f 的类型是 int&, 因ؓ (c) 是左?/code>
    decltype(0) g;        // g 的类型是 int, 因ؓ 0 是右?/code>
}

如果auto ?decltype 在一起用会是什么样子?能看下面的示例,下面q个CZ也是引入decltype的一个原?#8212;—让C++有能力写一?“ forwarding function 模板”Q?/p>

1
2
3
template< typename LHS, typename RHS>
  auto AddingFunc(const LHS &lhs, const RHS &rhs) -> decltype(lhs+rhs)
{return lhs + rhs;}

q个函数模板看v来相当费解,其用Cauto ?decltype 来扩展了已有的模板技术的不。怎么个不_Q在上例中,我不知道AddingFunc会接收什么样cd的对象,q两个对象的 + 操作W返回的cd也不知道Q老的模板函数无法定义AddingFuncq回值和q两个对象相加后的返回值匹配,所以,你可以用上q的q种定义?/p>

l一的初始化语法

C/C++的初始化的方法比较,C++ 11 用大括号l一了这些初始化的方法?/p>

比如QPOD的类型?/p>

1
2
int arr[4]={0,1,2,3};
struct tm today={0};

关于POD相说两句Q所谓POD是Plain Old DataQ当class/struct?em>极简?trivial)、属?em>标准布局(standard-layout)Q以及他的所有非静态(non-staticQ成员都是PODӞ会被视ؓPOD。如Q?/p>

1
2
3
struct A { int m; }; // POD
struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
struct C { C() : m() {}; ~C(); int m; }; // non-POD, default-initialising m

POD的初始化有点怪,比如上例Qnew A; 和new A(); 是不一LQ对于其内部的mQ前者没有被初始化,后者被初始化了Q不?的编译器行ؓ不一PVC++和GCC不一P。而非POD的初始化Q则都会被初始化?/p>

从这点可以看出,C/C++的初始化问题很奇怪,所以,在C++ 2011版中做了统一。原文作者给Z如下的示例:

1
2
3
4
5
6
7
8
9
C c {0,0}; //C++11 only. 相当? C c(0,0);
 
int* a = new int[3] { 1, 2, 0 }; /C++11 only
 
class X {
    int a[4];
    public:
        X() : a{1,2,3,4} {} //C++11, member array initializer
};

容器的初始化Q?/p>

1
2
3
4
5
// C++11 container initializer
vector<string> vs={ "first", "second", "third"};
map singers =
{ {"Lady Gaga", "+1 (212) 555-7890"},
{"Beyonce Knowles", "+1 (212) 555-0987"}};

q支持像Java一L成员初始化:

1
2
3
4
5
6
class C
{
   int a=7; //C++11 only
 public:
   C();
};

Delete ?Default 函数

我们知道C++的编译器在你没有定义某些成员函数的时候会l你的类自动生成q些函数Q比如,构造函敎ͼ拯构造,析构函数Q赋值函数。有些时候,我们不想要这些函敎ͼ比如Q构造函敎ͼ因ؓ我们惛_实现单例模式。传l的做法是将其声明成privatecd?/p>

在新的C++中引入了两个指示W,delete意ؓ告诉~译器不自动产生q个函数Qdefault告诉~译器生一个默认的。原文给Z下面两个例子Q?/p>

1
2
3
4
5
struct A
{
    A()=default; //C++11
    virtual ~A()=default; //C++11
};

再如delete

1
2
3
4
5
6
7
struct NoCopy
{
    NoCopy & operator =( const NoCopy & ) = delete;
    NoCopy ( const NoCopy & ) = delete;
};
NoCopy a;
NoCopy b(a); //compilation error, copy ctor is deleted

q里Q我惌一下,Z么我们需要defaultQ我什么都不写不就是default吗?不全然是Q比如构造函敎ͼ因ؓ只要你定义了一个构造函敎ͼ~译器就不会l你生成一个默认的了。所以,Z要让默认的和自定义的共存Q才引入q个参数Q如下例所C:

1
2
3
4
5
struct SomeType
{
 SomeType() = default; // 使用~译器生成的默认构造函?/code>
 SomeType(OtherType value);
};

关于deleteq有两个有用的地Ҏ

1Q让你的对象只能生成在栈内存上:

1
2
3
struct NonNewable {
    void *operator new(std::size_t) = delete;
};

2Q阻止函数的其Ş参的cd调用Q(若尝试以 double 的Ş参调?nbsp;f()Q将会引发编译期错误Q?~译器不会自动将 double 形参转型?int 再调?code>f()Q如果传入的参数是doubleQ则会出现编译错误)

1
2
void f(int i);
 void f(double) = delete;

nullptr

C/C++的NULL宏是个被有很多潜在BUG的宏。因为有的库把其定义成整?Q有的定义成 (void*)0。在C的时代还好。但是在C++的时代,q就会引发很多问题。你可以上网看看。这是ؓ什么需?nbsp;nullptr 的原因?nbsp;nullptr 是强cd的?/p>

1
2
3
4
5
6
void f(int); //#1
void f(char *);//#2
//C++03
f(0); //二义?/code>
//C++11
f(nullptr) //无二义性,调用f(char*)

所以在新版中请?nullptr 初始化指针?/p>

委托构?/h4>

在以前的C++中,构造函C间不能互相调用,所以,我们在写q些怼的构造函数里Q我们会把相同的代码攑ֈ一个私有的成员函数中?/p>

1
2
3
4
5
6
7
8
9
10
class SomeType {
private:
  int number;
  string name;
  SomeType( int i, string&amp; s ) : number(i), name(s){}
public:
  SomeType( )               : SomeType( 0, "invalid" ){}
  SomeType( int i )         : SomeType( i, "guest" ){}
  SomeType( string&amp; s ) : SomeType( 1, s ){ PostInit(); }
};

但是Qؓ了方便ƈ不?#8220;委托构?#8221;q个事出玎ͼ最主要的问题是Q基cȝ构造不能直接成为派生类的构造,q是基cȝ构造函数够了,zc还要自己写自己的构造函敎ͼ

1
2
3
4
5
6
7
8
9
10
11
class BaseClass
{
public:
  BaseClass(int iValue);
};
 
class DerivedClass : public BaseClass
{
public:
  using BaseClass::BaseClass;
};

上例中,zcL动承基cȝ构造函敎ͼ ~译器可以用基cȝ构造函数完成派生类的构造?而将基类的构造函数带入派生类的动?无法选择性地部分带入Q?所以,要不是l承基类全部的构造函敎ͼ要不是一个都不?不手动带??此外Q若牉|到多重承,从多个基cȝ承而来的构造函C可以有相同的函数{֐(signature)?而派生类的新加入的构造函C不可以和l承而来的基cL造函数有相同的函数签名,因ؓq相当于重复声明。(所谓函数签名就是函数的参数cd和顺序不Q?/p>

叛_引用和move语义

在老版的C++中,临时性变量(UCؓ叛_?#8221;R-values”Q位于赋值操作符之右Q经常用作交换两个变量。比如下面的CZ中的tmp变量。示例中的那个函数需要传递两个string的引用,但是在交换的q程中生了对象的构造,内存的分配还有对象的拯构造等{动作,成本比较高?/p>

1
2
3
4
5
6
void naiveswap(string &amp;a, string &amp;b)
{
 string temp = a;
 a=b;
 b=temp;
}

C++ 11增加一个新的引用(referenceQ类型称作右值引用(R-value referenceQ,标记?tt>typename &&。他们能够以non-const值的方式传入Q允许对象去改动他们。这修正允许特定对象创造出move语义?/p>

举例而言Q上面那个例子中QstringcM保存了一个动态内存分存的char*指针Q如果一个string对象发生拯构造(如:函数q回Q,stringc里的char*内存只能通过创徏一个新的时对象,q把函数内的对象的内存copy到这个新的对象中Q然后销毁时对象及其内存?strong>q是原来C++性能上重点被批评的事?/p>

能过叛_引用,string的构造函数需要改?#8220;move构造函?#8221;Q如下所C。这样一来,使得Ҏ?span style="font-family: monospace">stirng的右值引用可以单U地从右值复制其内部C-style的指针到新的stringQ然后留下空的右倹{这个操作不需要内存数l的复制Q而且I的暂时对象的析构也不会释放内存。其更有效率?/p>

1
2
3
4
5
class string
{
    string (string&&); //move constructor
    string&& operator=(string&&); //move assignment operator
};

The C++11 STL中广泛地使用了右值引用和move语议。因此,很多法和容器的性能都被优化了?/p>

C++ 11 STL 标准?/h4>

C++ STL库在2003q经历了很大的整Ҏ?nbsp;Library Technical Report 1 (TR1)?TR1 中出C很多新的容器c?(unordered_set, unordered_map, unordered_multiset, ?nbsp;unordered_multimap) 以及一些新的库支持诸如Q正则表辑ּQ?tuplesQ函数对象包装,{等?C++11 批准?TR1 成ؓ正式的C++标准Q还有一些TR1 后新加的一些库Q从而成Z新的C++ 11 STL标准库。这个库主要包含下面的功能:

U程?/h5>

q们׃多说了,以前的STL饱受U程安全的批评。现在好 了。C++ 11 支持U程cM。这涉及两个部分:W一、设计一个可以多个U程在一个进E中共存的内存模型;W二、ؓU程之间的交互提供支持。第二部分将q序库提供支持。大家可以看?a target="_blank">promises and futuresQ其用于对象的同步?nbsp;async() 函数模板用于发vq发dQ?nbsp;thread_local 为线E内的数据指定存储类型。更多的东西Q可以查?Anthony Williams?nbsp;Simpler Multithreading in C++0x.

新型指针

C++98 的知能指针是 auto_ptrQ?在C++ 11中被废弃了?/code>C++11  引入了两个指针类Q?nbsp;shared_ptr ?unique_ptr?shared_ptr只是单纯的引用计数指针,unique_ptr 是用来取?code>auto_ptr?nbsp;unique_ptr 提供 auto_ptr 大部份特性,唯一的例外是 auto_ptr 的不安全、隐性的左值搬UR不?nbsp;auto_ptrQ?code>unique_ptr 可以存放?C++0x 提出的那些能察觉搬移动作的容器之中?/p>

Z么要q么qԌ大家可以看看《More Effective C++》中?auto_ptr的讨论?/p>

新的法

定义了一些新的算法: all_of(), any_of() ?nbsp;none_of()?/code>

1
2
3
4
5
6
7
8
#include &lt;algorithm&gt;
//C++11 code
//are all of the elements positive?
all_of(first, first+n, ispositive()); //false
//is there at least one positive element?
any_of(first, first+n, ispositive());//true
// are none of the elements positive?
none_of(first, first+n, ispositive()); //false

使用新的copy_n()法Q你可以很方便地拯数组?/p>

1
2
3
4
5
#include &lt;algorithm&gt;
int source[5]={0,12,34,50,80};
int target[5];
//copy 5 elements from source to target
copy_n(source,5,target);

使用 iota() 可以用来创徏递增的数列。如下例所C:

1
2
3
4
5
include &lt;numeric&gt;
int a[5]={0};
char c[3]={0};
iota(a, a+5, 10); //changes a to {10,11,12,13,14}
iota(c, c+3, 'a'); //{'a','b','c'}

MQ看下来QC++11 q是很学院派Q很多实用的东西q是没有Q比如: XMLQsocketsQreflectionQ当然还有垃圑֛收。看来要{到C++ 20了。呵c不qC++ 11在性能上还是很快。参?Google’s benchmark tests。原文还引用Stroustrup 的观点:C++11 是一门新的语a——一个更好的 C++?/p>

如果把所有的改变都列出来Q你会发现真多啊。我估计C++ Primer那本书的厚度要增加至?0%以上。C++的门槛会不会来高了呢Q我不知道,但我个h觉得q门语言的确是变得越来越令h望而却步了。(惌v了某人和我说的一句话——学技术真的是太篏了,q是搞方法论好؜些?Q?/p>

]]>
各编译器对于C++11新特性的支持情况http://www.shnenglu.com/tianbianlan/archive/2013/05/05/199991.html天边?/dc:creator>天边?/author>Sun, 05 May 2013 13:11:00 GMThttp://www.shnenglu.com/tianbianlan/archive/2013/05/05/199991.htmlhttp://www.shnenglu.com/tianbianlan/comments/199991.htmlhttp://www.shnenglu.com/tianbianlan/archive/2013/05/05/199991.html#Feedback0http://www.shnenglu.com/tianbianlan/comments/commentRss/199991.htmlhttp://www.shnenglu.com/tianbianlan/services/trackbacks/199991.htmlhttp://wiki.apache.org/stdcxx/C%2B%2B0xCompilerSupport
The following table lists C++0x features and their support in popular compilers.

Status Of C++ 0x Language Features in Compilers

C++ 0x FEATURE

PAPER(S)

HP aCC

EDG eccp

GCC

Intel C++

MSVC

IBM XLC++

Sun/ Oracle C++

Embarcadero C++ Builder

Digital Mars C++

Clang

alignas

N2341

4.8

3.0

alignof

N2341

4.5

Yes

2.9

Atomic operations

N2427

4.4

13.0

11.0

3.1

auto

v0.9: N1984, v1.0: N2546

4.1(v0.9)

4.4(v1.0)

11.0(v0.9)

10.0(v0.9)

11.1 (V1.0)

Yes

C99 preprocessor

N1653

4.3

11.1

10.1

5.9

Yes

Yes

Concepts [removed]

N2617

ConceptGcc


constexpr

N2235

4.6

13.0

12.1

3.1

decltype

v1.0: N2343, v1.1: N3276

4.1(v1.0)

4.3(v1.0) 4.8.1(v1.1)

11.0(v1.0)

10.0(v1.0), 11.0(v1.1)

11.1 (V1.0)

Yes

2.9

Defaulted And Deleted Functions

N2346

4.1

4.4

12.0

3.0

Delegating Constructors

N1986

4.7


11.0 nov'12

11.1

3.0

Explicit conversion operators

N2437

4.5

13.0

11.0 nov'12

12.1

Yes

3.0

Extended friend Declarations

N1791

4.1

4.7

11.0

10.0***

V1R11,11.1

2.9

extern template

N1987

3, 5, 6

3.3

9

6.0

V1R11,11.1

Yes

Yes

Forward declarations for enums

N2764

4.6

11.0

12.1

3.1

Inheriting Constructors

N2540

4.8



Initializer Lists

N2672

4.4

13.0

11.0 nov'12

3.1

Lambda expressions and closures

v0.9: N2550, v1.0: N2658, v1.1: N2927

4.1(v0.9)

4.5(v1.1)

11.0(v0.9)
12.0(v1.0)

10.0(v1.0), 11.0(v1.1)

3.1

Local and Unnamed Types as Template Arguments

N2657

4.5

12.0

10.0

2.9

long long

N1811

Yes

Yes

Yes

Yes

Yes

Yes

Yes

Yes

Yes

Yes

Namespace Association

N2535

4.4


11.1

2.9

New character types

N2249

4.4

2.9

New function declaration syntax for deduced return types

N2541

4.1

4.4

12.1

10.0

12.1

2.9

nullptr

N2431

4.6

12.1*

10.0

2.9

Unicode String Literals

N2442

4.4

11.0*

5.7

Yes

3.0

Raw String Literals

N2442

4.5


11.0 nov'12

Yes

User-defined Literals

N2765

4.7

3.1

Right Angle Brackets

N1757

4.1

4.3

11.0

8.0

12.1

Yes

R-Value References, std::move

v1.0: N2118, v2.0: N2844, v2.1: N2844+, v3.0: N3053

4.1(v1.0)

4.3(v1.0)
4.5(v2.1)
4.6(v3.0)

11.1(v1.0)
12.0(v2.0)

10.0(v2.0), 11.0(v2.1)

12.1(v2.1)

Yes

Yes

static_assert

N1720

4.1

4.3

11.0

10.0

11.1

Yes

2.9

Strongly-typed enums

N2347

4.4

12.0

11.0

12.1

Yes

2.9

Template aliases

N2258

4.7

12.1

3.0

Thread-Local Storage

N2659

4.8 (4.4****)

11.1***

10.0***

5.9***

2.9****

Unrestricted Unions

N2544

4.6


3.0

Built-in Type Traits

N1836

6.16

4.0

4.3

10.0

8.0

Yes

3.0

Variadic Templates

v0.9: N2242, v1.0: N2555

4.1(v0.9)

4.3(v0.9) 4.4(v1.0)

12.1(v0.9)

11.0 nov'12

11.1 (v0.9)

2.9(1.0)

Range-based for-loop

N2930

4.6

13.0

11.0

3.0

override and final

v0.8: N2928, v0.9: N3206, v1.0: N3272

4.7

12.0(v0.8)***

8.0(v0.8)*** 11.0(v1.0)

2.9

Attributes

N2761

4.8

12.1

ref-qualifiers

N2439

4.8.1

2.9

Non-static data member initializers

N2756

4.7

3.0

Dynamic initialization and destruction with concurrency (Magic statics)

N2660

4.3

?

2.9

* — 1) unicode string literals is a feature of the EDG frontend, but it is undocumented at Intel C++ compiler (/Qoption,cpp,"--uliterals" option enables it)



]]>
gprof——GNU性能分析工具 http://www.shnenglu.com/tianbianlan/archive/2013/04/22/199639.html天边?/dc:creator>天边?/author>Mon, 22 Apr 2013 08:39:00 GMThttp://www.shnenglu.com/tianbianlan/archive/2013/04/22/199639.htmlhttp://www.shnenglu.com/tianbianlan/comments/199639.htmlhttp://www.shnenglu.com/tianbianlan/archive/2013/04/22/199639.html#Feedback0http://www.shnenglu.com/tianbianlan/comments/commentRss/199639.htmlhttp://www.shnenglu.com/tianbianlan/services/trackbacks/199639.html转蝲?/em>http://www.cnblogs.com/feisky/archive/2010/03/09/1681997.html

gprof介绍

gprof是GNU profiler工具。可以显C程序运行的“flat profile”Q包括每个函数的调用ơ数Q每个函数消耗的处理器时间。也可以昄“调用?#8221;Q包括函数的调用关系Q每个函数调用花费了多少旉。还可以昄“注释的源代码”Q是E序源代码的一个复本,标记有程序中每行代码的执行次数?/p>

为gprof~译E序


在编译或链接源程序的时候在~译器的命o行参C加入“-pg”选项Q编译时~译器会自动在目标代码中插入用于性能试的代码片断,q些代码在程序在q行旉集ƈ记录函数的调用关pd调用ơ数Q以及采集ƈ记录函数自n执行旉和子函数的调用时_E序q行l束后,会在E序退出的路径下生成一个gmon.out文g。这个文件就是记录ƈ保存下来的监控数据。可以通过命o行方式的gprof或图形化的Kprof来解读这些数据ƈ对程序的性能q行分析。另外,如果x看库函数的profilingQ需要在~译是再加入“-lc_p”~译参数代替“-lc”~译参数Q这L序会链接libc_p.a库,才可以生库函数的profiling信息。如果想执行一行一行的profilingQ还需要加?#8220;-g”~译参数?br />例如如下命o行:gcc -Wall -g -pg -lc_p example.c -o example

Gprof基本用法Q?/em>

1Q?使用 -pg ~译和链接你的应用程序?/p>

2Q?执行你的应用E序使之生成供gprof 分析的数据?

3Q?使用gprof E序分析你的应用E序生成的数据?

$gprof -b a.out gmon.out      
Flat profile:

Each sample counts as 0.01 seconds.
no time accumulated

  %   cumulative   self              self     total          
time   seconds   seconds    calls  Ts/call  Ts/call  name   
  0.00      0.00     0.00        1     0.00     0.00  function

                        Call graph

granularity: each sample hit covers 2 byte(s) no time propagated

index % time    self  children    called     name
                0.00    0.00       1/1           main [8]
[1]      0.0    0.00    0.00       1         function [1]
-----------------------------------------------

Index by function name

   [1] function

gprof产生的信?/h1>


%                        the percentage of the total running time of the
time                     program used by this function.
                           函数使用旉占所有时间的癑ֈ比?br />cumulative          a running sum of the number of seconds accounted
seconds             for by this function and those listed above it.
                           函数和上列函数篏计执行的旉?br />self                    the number of seconds accounted for by this
seconds             function alone.  This is the major sort for this
                          listing.
                          函数本n所执行的时间?br />calls                   the number of times this function was invoked, if
                          this function is profiled, else blank.
                          函数被调用的ơ数
self                   the average number of milliseconds spent in this
ms/call               function per call, if this function is profiled,
                         else blank.
                          每一ơ调用花费在函数的时间microseconds?br />total                  the average number of milliseconds spent in this
ms/call               function and its descendents per call, if this
                          function is profiled, else blank.
                          每一ơ调用,p在函数及其衍生函数的q_旉microseconds?br />name                 the name of the function.  This is the minor sort
                          for this listing. The index shows the location of
                          the function in the gprof listing. If the index is
                          in parenthesis it shows where it would appear in
                          the gprof listing if it were to be printed.
                          函数?/p>

命o格式

gprof [可执行文件] [gmon.out文g] [其它参数]

Ҏ号中的内容可以省略。如果省略了“可执行文?#8221;Qgprof会在当前目录下搜索a.out文g作ؓ可执行文Ӟ而如果省略了gmon.out文gQgprof也会在当前目录下Lgmon.out。其它参数可以控制gprof输出内容的格式等信息。最常用的参数如下:

l -b 不再输出l计图表中每个字D늚详细描述?

l -p 只输出函数的调用图(Call graph的那部分信息Q?

l -q 只输出函数的旉消耗列表?

l -e Name 不再输出函数Name 及其子函数的调用图(除非它们有未被限制的其它父函敎ͼ。可以给定多?-e 标志。一?-e 标志只能指定一个函数?

l -E Name 不再输出函数Name 及其子函数的调用图,此标志类g -e 标志Q但它在L间和癑ֈ比时间的计算中排除了由函数Name 及其子函数所用的旉?

l -f Name 输出函数Name 及其子函数的调用图。可以指定多?-f 标志。一?-f 标志只能指定一个函数?

l -F Name 输出函数Name 及其子函数的调用图,它类g -f 标志Q但它在L间和癑ֈ比时间计中仅用所打印的例E的旉。可以指定多?-F 标志。一?-F 标志只能指定一个函数?F 标志覆盖 -E 标志?

l -z 昄使用ơ数为零的例E(按照调用计数和篏U时间计)?

不过,gprof不能昄对象之间的承关p?q也是它的弱?



]]>
【{】浅析系l的大小端模?http://www.shnenglu.com/tianbianlan/archive/2012/01/19/164364.html天边?/dc:creator>天边?/author>Thu, 19 Jan 2012 03:39:00 GMThttp://www.shnenglu.com/tianbianlan/archive/2012/01/19/164364.htmlhttp://www.shnenglu.com/tianbianlan/comments/164364.htmlhttp://www.shnenglu.com/tianbianlan/archive/2012/01/19/164364.html#Feedback0http://www.shnenglu.com/tianbianlan/comments/commentRss/164364.htmlhttp://www.shnenglu.com/tianbianlan/services/trackbacks/164364.html

转蝲来源Q?a >http://blog.csdn.net/dragonbooker/article/details/6173321
大端模式

  所谓的大端模式Q是指数据的低位Q就是权D的后面那几位)保存在内存的高地址中,而数据的高位Q保存在内存的低地址中,q样的存储模式有点儿cM于把数据当作字符串顺序处理:地址由小向大增加Q而数据从高位往低位放;

 

端模式

  所谓的端模式Q是指数据的低位保存在内存的低地址中,而数 据的高位保存在内存的高地址中,q种存储模式地址的高低和数据位权有效地结合v来,高地址部分权值高Q低地址部分权gQ和我们的逻辑Ҏ一致?/span>

 

Z么有大小端模式之?/span>

Z么会有大端模式之分呢?q是因ؓ在计机pȝ中,我们是以字节为单位的Q每个地址单元都对应着一个字节,一个字节ؓ 8bit。但是在C语言中除?/span>8bit?/span>char之外Q还?/span>16bit?/span>short型,32bit?/span>long型(要看具体的编译器Q,另外Q对于位数大?/span> 8位的处理器,例如16位或?/span>32位的处理器,׃寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就D了大端存储模式和端存储模式。例如一?/span>16bit?/span>short?/span>xQ在内存中的地址?/span>0x0010Q?/span>x的gؓ0x1122Q那?/span>0x11为高字节Q?/span>0x22Z字节。对?/span> 大端模式Q就?/span>0x11攑֜低地址中,?/span>0x0010中,0x22攑֜高地址中,?/span>0x0011中。小端模式,刚好相反。我们常用的X86l构是小端模式,?/span>KEIL C51则ؓ大端模式。很多的ARMQ?/span>DSP都ؓ端模式。有?/span>ARM处理器还可以q件来选择是大端模式还是小端模式?/span>

二、D例说?/span>

大家都知道字W?#8216;A’?/span>ASCII码gؓ65Q十q制Q也是0x41Q那么这个值在不同大小端模式的pȝ中存攄方式分别为:

大端模式Q?/span>00 00 00 41 -----高低模式

端模式Q?/span>41 00 00 00  -----低低模式

三、用代码判断大端模式

可以通过声明一个联合(unionQ判断大端模式Q?/span>

 

/**

 * Ҏ一 得到当前pȝ的大端属?/span>, 此方法要保证?/span>32位机试

 */

static union {

       char c[4];

    unsigned long l;

}

 

endian_test = { { 'l', '?', '?', 'b' } };   

 

#define ENDIANNESS ((char)endian_test.l)

 

/**

 * Ҏ?/span>: 得到当前pȝ的大端属?/span>

 */

static union {

     short n;

     char c[sizeof(short)];

}un;

 

int getEndian()

{

   un.n = 0x0102;

 

   if ((un.c[0] == 1 && un.c[1] == 2))

   {

     printf("big endian/n");

   }

   else if ((un.c[0] == 2 && un.c[1] == 1))

   {

     printf("little endian/n");

   }

   else

     printf("error!/n");

 

   return 0;

}

 

/**

 * Ҏ?/span>: 得到当前pȝ的大端属?/span>

 */

int getEndian()

{

   int c = 1;                               // big-endian: 00 00 00 01 little-endian: 01 00 00 00

  // int c = 0x02000001;          // big-endian: 02 00 00 01 little-endian: 01 00 00 02

 

   if ((*(char *)&c) == 1)               // ?/span>c变量所在地址上的一个字节?/span>

   {

     printf("little endian/n");

   }

   else

     printf("big endian");

 

   return 0;

}



]]>
【{】TCP三次握手/四次挥手详解 http://www.shnenglu.com/tianbianlan/archive/2012/01/11/164020.html天边?/dc:creator>天边?/author>Wed, 11 Jan 2012 15:49:00 GMThttp://www.shnenglu.com/tianbianlan/archive/2012/01/11/164020.htmlhttp://www.shnenglu.com/tianbianlan/comments/164020.htmlhttp://www.shnenglu.com/tianbianlan/archive/2012/01/11/164020.html#Feedback0http://www.shnenglu.com/tianbianlan/comments/commentRss/164020.htmlhttp://www.shnenglu.com/tianbianlan/services/trackbacks/164020.htmlhttp://blog.csdn.net/sfwork/article/details/6876692
1、徏立连接协议(三次握手Q?wbr>
Q?Q客L发送一个带SYN标志的TCP报文到服务器。这是三ơ握手过E中的报??br />Q?Q?服务器端回应客户端的Q这是三ơ握手中的第2个报文,q个报文同时带ACK标志和SYN标志。因此它表示对刚才客LSYN报文的回应;同时又标志SYNl客LQ询问客L是否准备好进行数据通讯?br />Q?Q?客户必须再次回应服务D一个ACK报文Q这是报文段3?br />2、连接终止协议(四次挥手Q?wbr>
   ׃TCPq接是全双工的,因此每个方向都必d独进行关闭。这原则是当一方完成它的数据发送Q务后p发送一个FIN来终止这个方向的q接。收C?FIN只意味着q一方向上没有数据流动,一个TCPq接在收C个FIN后仍能发送数据。首先进行关闭的一方将执行d关闭Q而另一Ҏ行被动关闭?br /> Q?Q?TCP客户端发送一个FINQ用来关闭客户到服务器的数据传送(报文D?Q?br /> Q?Q?服务器收到这个FINQ它发回一个ACKQ确认序号ؓ收到的序号加1Q报文段5Q。和SYN一P一个FIN占用一个序受?br /> Q?Q?服务器关闭客L的连接,发送一个FINl客LQ报文段6Q?br /> Q?Q?客户D发回ACK报文认Qƈ确认序可|ؓ收到序号?Q报文段7Q?br />CLOSED: q个没什么好说的了,表示初始状态?br />LISTEN: q个也是非常Ҏ理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受q接了?br />SYN_RCVD: q个状态表C接受到了SYN报文Q在正常情况下,q个状态是服务器端的SOCKET在徏立TCPq接时的三次握手会话q程中的一个中间状态,很短暂,基本上用netstat你是很难看到q种状态的Q除非你Ҏ写了一个客L试E序Q故意将三次TCP握手q程中最后一个ACK报文不予发送。因此这U状态时Q当收到客户端的ACK报文后,它会q入到ESTABLISHED状态?br />SYN_SENT: q个状态与SYN_RCVD遥想呼应Q当客户端SOCKET执行CONNECTq接Ӟ它首先发送SYN报文Q因此也随即它会q入CSYN_SENT状态,q等待服务端的发送三ơ握手中的第2个报文。SYN_SENT状态表C客L已发送SYN报文?br />ESTABLISHEDQ这个容易理解了Q表C接已l徏立了?br />FIN_WAIT_1: q个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示{待Ҏ的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时Q它想主动关闭连接,向对方发送了FIN报文Q此时该SOCKET卌入到FIN_WAIT_1状态。而当Ҏ回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论Ҏ何种情况下,都应该马上回应ACK报文Q所以FIN_WAIT_1状态一般是比较难见到的Q而FIN_WAIT_2状态还有时常常可以用netstat看到?br />FIN_WAIT_2Q上面已l详l解释了q种状态,实际上FIN_WAIT_2状态下的SOCKETQ表C半q接Q也x一方要求closeq接Q但另外q告诉对方,我暂时还有点数据需要传送给你,E后再关闭连接?br />TIME_WAIT: 表示收到了对方的FIN报文Qƈ发送出了ACK报文Q就{?MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下Q收CҎ同时带FIN标志和ACK标志的报文时Q可以直接进入到TIME_WAIT状态,而无ȝqFIN_WAIT_2状态?br />CLOSING: q种状态比较特D,实际情况中应该是很少见,属于一U比较罕见的例外状态。正常情况下Q当你发送FIN报文后,按理来说是应该先收到Q或同时收到Q对方的ACK报文Q再收到Ҏ的FIN报文。但是CLOSING状态表CZ发送FIN报文后,q没有收到对方的ACK报文Q反而却也收CҎ的FIN报文。什么情况下会出现此U情况呢Q其实细想一下,也不隑־出结论:那就是如果双方几乎在同时close一个SOCKET的话Q那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKETq接?br />CLOSE_WAIT: q种状态的含义其实是表C在{待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文l自己,你系l毫无疑问地会回应一个ACK报文l对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给ҎQ如果没有的话,那么你也可以closeq个SOCKETQ发送FIN报文l对方,也即关闭q接。所以你在CLOSE_WAIT状态下Q需要完成的事情是等待你d闭连接?br />LAST_ACK: q个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以q入到CLOSED可用状态了?br />最后有2个问题的回答Q我自己分析后的l论Q不一定保?00%正确Q?br />1?Z么徏立连接协议是三次握手Q而关闭连接却是四ơ握手呢Q?br />q是因ؓ服务端的LISTEN状态下的SOCKET当收到SYN报文的徏q请求后Q它可以把ACK和SYNQACK起应{作用,而SYN起同步作用)攑֜一个报文里来发送。但关闭q接Ӟ当收到对方的FIN报文通知Ӟ它仅仅表C对Ҏ有数据发送给你了Q但未必你所有的数据都全部发送给Ҏ了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给Ҏ之后Q再发送FIN报文l对Ҏ表示你同意现在可以关闭连接了Q所以它q里的ACK报文和FIN报文多数情况下都是分开发送的?br />2?Z么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?
q是因ؓQ虽然双斚w同意关闭q接了,而且握手?个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(好比从SYN_SEND状态到ESTABLISH状态那PQ但是因为我们必要假想|络是不可靠的,你无法保证你最后发送的ACK报文会一定被Ҏ收到Q因此对方处于LAST_ACK状态下的SOCKET可能会因时未收到ACK报文Q而重发FIN报文Q所以这个TIME_WAIT状态的作用是用来重发可能丢失的ACK报文?img src ="http://www.shnenglu.com/tianbianlan/aggbug/164020.html" width = "1" height = "1" />

]]>
B+数的实现--优秀代码http://www.shnenglu.com/tianbianlan/archive/2011/11/08/159814.html天边?/dc:creator>天边?/author>Tue, 08 Nov 2011 04:32:00 GMThttp://www.shnenglu.com/tianbianlan/archive/2011/11/08/159814.htmlhttp://www.shnenglu.com/tianbianlan/comments/159814.htmlhttp://www.shnenglu.com/tianbianlan/archive/2011/11/08/159814.html#Feedback0http://www.shnenglu.com/tianbianlan/comments/commentRss/159814.htmlhttp://www.shnenglu.com/tianbianlan/services/trackbacks/159814.htmlhttp://idlebox.net/2007/stx-btree/


]]>
[转]C++ 对象的内存布局 http://www.shnenglu.com/tianbianlan/archive/2010/04/29/113987.html天边?/dc:creator>天边?/author>Thu, 29 Apr 2010 11:30:00 GMThttp://www.shnenglu.com/tianbianlan/archive/2010/04/29/113987.htmlhttp://www.shnenglu.com/tianbianlan/comments/113987.htmlhttp://www.shnenglu.com/tianbianlan/archive/2010/04/29/113987.html#Feedback0http://www.shnenglu.com/tianbianlan/comments/commentRss/113987.htmlhttp://www.shnenglu.com/tianbianlan/services/trackbacks/113987.html
2008-11-14 作者:陈皓 来源Qcsdn


前言

07q?2月,我写了一《C++虚函数表解析》的文章Q引起了大家的兴。有很多朋友Ҏ的文章留了言Q有鼓励我的Q有批评我的Q还有很多问问题的。我在这里一q对大家的留a表示感谢。这也是我ؓ什么再写一箋a的原因。因为,在上一文章中Q我用了的示例都是非常简单的Q主要是Z说明一些机理上的问题,也是Z图一些表达上方便和简单。不惻Iq篇文章成ؓ了打开C++对象模型内存布局的一个引子,引发了大家对C++对象的更深层ơ的讨论。当Ӟ我之前的文章q有很多斚w没有涉及Q从我个人感觉下来,在谈函数表里Q至有以下q些内容没有涉及Q?/p>

1Q有成员变量的情c?/p>

2Q有重复l承的情c?/p>

3Q有虚拟l承的情c?/p>

4Q有ȝ型虚拟承的情况?/p>

q些都是我本文章需要向大家说明的东ѝ所以,q篇文章会是《C++虚函数表解析》的一个箋,也是一高U进阶的文章。我希望大家在读q篇文章之前对C++有一定的基础和了解,q能先读我的上一文章。因文章的深度可能会比较深Q而且会比较杂乱,我希望你在读本篇文章时不会有大脑思维紊ؕD大脑L的情c?-)

对象的媄响因?/p>

而言之,我们一个类可能会有如下的媄响因素:

1Q成员变?/p>

2Q虚函数Q生虚函数表)

3Q单一l承Q只l承于一个类Q?/p>

4Q多重承(l承多个c)

5Q重复承(l承的多个父cM其父cL相同的超c)

6Q虚拟承(使用virtual方式l承Qؓ了保证承后父类的内存布局只会存在一份)

上述的东襉K常是C++q门语言在语义方面对对象内部的媄响因素,当然Q还会有~译器的影响Q比如优化)Q还有字节对齐的影响。在q里我们都不讨论Q我们只讨论C++语言上的影响?/p>

本篇文章着重讨Zq几个情况下的C++对象的内存布局情况?/p>

1Q单一的一般承(带成员变量、虚函数、虚函数覆盖Q?/p>

2Q单一的虚拟承(带成员变量、虚函数、虚函数覆盖Q?/p>

3Q多重承(带成员变量、虚函数、虚函数覆盖Q?/p>

4Q重复多重承(带成员变量、虚函数、虚函数覆盖Q?/p>

5Q钻矛_的虚拟多重承(带成员变量、虚函数、虚函数覆盖Q?/p>

我们的目标就是,让事情越来越复杂?/p>

知识复习

我们单地复习一下,我们可以通过对象的地址来取得虚函数表的地址Q如Q?/p>

typedef void(*Fun)(void);

Base b;

Fun pFun = NULL;

cout << "虚函数表地址Q? << (int*)(&b) << endl;

cout << "虚函数表 ?W一个函数地址Q? << (int*)*(int*)(&b) << endl;

// Invoke the first virtual function

pFun = (Fun)*((int*)*(int*)(&b));

pFun();

我们同样可以用这U方式来取得整个对象实例的内存布局。因些东西在内存中都是连l分布的Q我们只需要用适当的地址偏移量,我们可以获得整个内存对象的布局?/p>

本篇文章中的例程或内存布局主要使用如下~译器和pȝQ?/p>

1QWindows XP ?VC++ 2003

2QCygwin ?G++ 3.4.4

单一的一般?/strong>

下面Q我们假设有如下所C的一个承关p:

h意,在这个承关pMQ父c,子类Q孙子类都有自己的一个成员变量。而了c覆盖了父类的f()ҎQ孙子类覆盖了子cȝg_child()及其类的f()?/p>

我们的源E序如下所C:

class Parent {

public:

int iparent;

Parent ():iparent (10) {}

virtual void f() { cout << " Parent::f()" << endl; }

virtual void g() { cout << " Parent::g()" << endl; }

virtual void h() { cout << " Parent::h()" << endl; }

 

};

 

class Child : public Parent {

public:

int ichild;

Child():ichild(100) {}

virtual void f() { cout << "Child::f()" << endl; }

virtual void g_child() { cout << "Child::g_child()" << endl; }

virtual void h_child() { cout << "Child::h_child()" << endl; }

};

 

class GrandChild : public Child{

public:

int igrandchild;

GrandChild():igrandchild(1000) {}

virtual void f() { cout << "GrandChild::f()" << endl; }

virtual void g_child() { cout << "GrandChild::g_child()" << endl; }

virtual void h_grandchild() { cout << "GrandChild::h_grandchild()" << endl; }

};

我们使用以下E序作ؓ试E序Q(下面E序中,我用了一个int** pVtab 来作为遍历对象内存布局的指针,q样Q我可以方便地像用数l一h遍历所有的成员包括其虚函数表了Q在后面的程序中Q我也是用这LҎ的,请不必感到奇怪,Q?/p>

typedef void(*Fun)(void);

GrandChild gc;

int** pVtab = (int**)&gc;

cout << "[0] GrandChild::_vptr->" << endl;

for (int i=0; (Fun)pVtab[0][i]!=NULL; i++){

pFun = (Fun)pVtab[0][i];

cout << " ["<<i<<"] ";

pFun();

}

cout << "[1] Parent.iparent = " << (int)pVtab[1] << endl;

cout << "[2] Child.ichild = " << (int)pVtab[2] << endl;

cout << "[3] GrandChild.igrandchild = " << (int)pVtab[3] << endl;

其运行结果如下所C:Q在VC++ 2003和G++ 3.4.4下)

[0] GrandChild::_vptr->

    [0] GrandChild::f()

    [1] Parent::g()

    [2] Parent::h()

    [3] GrandChild::g_child()

    [4] Child::h1()

    [5] GrandChild::h_grandchild()

[1] Parent.iparent = 10

[2] Child.ichild = 100

[3] GrandChild.igrandchild = 1000

使用囄表示如下Q?/p>

可见以下几个斚wQ?/p>

1Q虚函数表在最前面的位|?/p>

2Q成员变量根据其l承和声明顺序依ơ放在后面?/p>

3Q在单一的承中Q被overwrite的虚函数在虚函数表中得到了更新?/p>

多重l承

下面Q再让我们来看看多重l承中的情况Q假设有下面q样一个类的承关pR注意:子类只overwrite了父cȝf()函数Q而还有一个是自己的函敎ͼ我们q样做的目的是ؓ了用g1()作ؓ一个标记来标明子类的虚函数表)。而且每个cM都有一个自q成员变量Q?/p>

我们的类l承的源代码如下所C:父类的成员初始ؓ10Q?0Q?0Q子cȝ?00

class Base1 {

public:

int ibase1;

Base1():ibase1(10) {}

virtual void f() { cout << "Base1::f()" << endl; }

virtual void g() { cout << "Base1::g()" << endl; }

virtual void h() { cout << "Base1::h()" << endl; }

 

};

class Base2 {

public:

int ibase2;

Base2():ibase2(20) {}

virtual void f() { cout << "Base2::f()" << endl; }

virtual void g() { cout << "Base2::g()" << endl; }

virtual void h() { cout << "Base2::h()" << endl; }

};

class Base3 {

public:

int ibase3;

Base3():ibase3(30) {}

virtual void f() { cout << "Base3::f()" << endl; }

virtual void g() { cout << "Base3::g()" << endl; }

virtual void h() { cout << "Base3::h()" << endl; }

};

class Derive : public Base1, public Base2, public Base3 {

public:

int iderive;

Derive():iderive(100) {}

virtual void f() { cout << "Derive::f()" << endl; }

virtual void g1() { cout << "Derive::g1()" << endl; }

};

我们通过下面的程序来查看子类实例的内存布局Q下面程序中Q注意我使用了一个s变量Q其中用Csizof(Base)来找下一个类的偏U量。(因ؓ我声明的是int成员Q所以是4个字节,所以没有对齐问题。关于内存的寚w问题Q大家可以自行试验,我在q里׃多说了)

typedef void(*Fun)(void);

Derive d;

int** pVtab = (int**)&d;

cout << "[0] Base1::_vptr->" << endl;

pFun = (Fun)pVtab[0][0];

cout << " [0] ";

pFun();

pFun = (Fun)pVtab[0][1];

cout << " [1] ";pFun();

pFun = (Fun)pVtab[0][2];

cout << " [2] ";pFun();

pFun = (Fun)pVtab[0][3];

cout << " [3] "; pFun();

pFun = (Fun)pVtab[0][4];

cout << " [4] "; cout<<pFun<<endl;

cout << "[1] Base1.ibase1 = " << (int)pVtab[1] << endl;

int s = sizeof(Base1)/4;

cout << "[" << s << "] Base2::_vptr->"<<endl;

pFun = (Fun)pVtab[s][0];

cout << " [0] "; pFun();

Fun = (Fun)pVtab[s][1];

cout << " [1] "; pFun();

pFun = (Fun)pVtab[s][2];

cout << " [2] "; pFun();

pFun = (Fun)pVtab[s][3];

out << " [3] ";

cout<<pFun<<endl;

cout << "["<< s+1 <<"] Base2.ibase2 = " << (int)pVtab[s+1] << endl;

s = s + sizeof(Base2)/4;

cout << "[" << s << "] Base3::_vptr->"<<endl;

pFun = (Fun)pVtab[s][0];

cout << " [0] "; pFun();

 

pFun = (Fun)pVtab[s][1];

cout << " [1] "; pFun();

pFun = (Fun)pVtab[s][2];

cout << " [2] "; pFun();

 

pFun = (Fun)pVtab[s][3];

cout << " [3] ";

cout<<pFun<<endl;

s++;

cout << "["<< s <<"] Base3.ibase3 = " << (int)pVtab[s] << endl;

s++;

cout << "["<< s <<"] Derive.iderive = " << (int)pVtab[s] << endl;

其运行结果如下所C:Q在VC++ 2003和G++ 3.4.4下)

[0] Base1::_vptr->

     [0] Derive::f()

     [1] Base1::g()

     [2] Base1::h()

     [3] Driver::g1()

     [4] 00000000      ç 注意Q在GCC下,q里?/span>1

[1] Base1.ibase1 = 10

[2] Base2::_vptr->

     [0] Derive::f()

     [1] Base2::g()

     [2] Base2::h()

     [3] 00000000      ç 注意Q在GCC下,q里?/span>1

[3] Base2.ibase2 = 20

[4] Base3::_vptr->

     [0] Derive::f()

     [1] Base3::g()

     [2] Base3::h()

     [3] 00000000

[5] Base3.ibase3 = 30

[6] Derive.iderive = 100

使用囄表示是下面这个样子:

我们可以看到Q?/p>

1Q?每个父类都有自己的虚表?/p>

2Q?子类的成员函数被攑ֈ了第一个父cȝ表中?/p>

3Q?内存布局中,其父cd局依次按声明顺序排列?/p>

4Q?每个父类的虚表中的f()函数都被overwrite成了子类的f()。这样做是Z解决不同的父cȝ型的指针指向同一个子cd例,而能够调用到实际的函数?/p>

重复l承

下面我们再来看看Q发生重复承的情况。所谓重复承,也就是某个基c被间接地重复承了多次?/p>

下图是一个承图Q我们重载了父类的f()函数?/p>

其类l承的源代码如下所C。其中,每个c都有两个变量,一个是整ŞQ?字节Q,一个是字符Q?字节Q,而且q有自己的虚函数Q自己overwrite父类的虚函数。如子类D中,f()覆盖了超cȝ函数Q?f1() 和f2() 覆盖了其父类的虚函数QDf()q虚函数?/p>

class B

{

public:

int ib;

char cb;

public:

B():ib(0),cb('B') {}

virtual void f() { cout << "B::f()" << endl;}

virtual void Bf() { cout << "B::Bf()" << endl;}

};

class B1 : public B

{

public:

int ib1;

char cb1;

public:

B1():ib1(11),cb1('1') {}

virtual void f() { cout << "B1::f()" << endl;}

virtual void f1() { cout << "B1::f1()" << endl;}

virtual void Bf1() { cout << "B1::Bf1()" << endl;}

};

class B2: public B

{

public:

int ib2;

char cb2;

public:

B2():ib2(12),cb2('2') {}

virtual void f() { cout << "B2::f()" << endl;}

virtual void f2() { cout << "B2::f2()" << endl;}

virtual void Bf2() { cout << "B2::Bf2()" << endl;}

};

class D : public B1, public B2

{

public:

int id;

char cd;

public:

D():id(100),cd('D') {}

virtual void f() { cout << "D::f()" << endl;}

virtual void f1() { cout << "D::f1()" << endl;}

virtual void f2() { cout << "D::f2()" << endl;}

virtual void Df() { cout << "D::Df()" << endl;}

};

我们用来存取子类内存布局的代码如下所C:Q在VC++ 2003和G++ 3.4.4下)

typedef void(*Fun)(void);

int** pVtab = NULL;

Fun pFun = NULL;

D d;

pVtab = (int**)&d;

cout << "[0] D::B1::_vptr->" << endl;

pFun = (Fun)pVtab[0][0];

cout << " [0] "; pFun();

pFun = (Fun)pVtab[0][1];

cout << " [1] "; pFun();

pFun = (Fun)pVtab[0][2];

cout << " [2] "; pFun();

pFun = (Fun)pVtab[0][3];

cout << " [3] "; pFun();

pFun = (Fun)pVtab[0][4];

cout << " [4] "; pFun();

pFun = (Fun)pVtab[0][5];

cout << " [5] 0x" << pFun << endl;

cout << "[1] B::ib = " << (int)pVtab[1] << endl;

cout << "[2] B::cb = " << (char)pVtab[2] << endl;

cout << "[3] B1::ib1 = " << (int)pVtab[3] << endl;

cout << "[4] B1::cb1 = " << (char)pVtab[4] << endl;

cout << "[5] D::B2::_vptr->" << endl;

pFun = (Fun)pVtab[5][0];

cout << " [0] "; pFun();

pFun = (Fun)pVtab[5][1];

cout << " [1] "; pFun();

pFun = (Fun)pVtab[5][2];

cout << " [2] "; pFun();

pFun = (Fun)pVtab[5][3];

cout << " [3] "; pFun();

pFun = (Fun)pVtab[5][4];

cout << " [4] 0x" << pFun << endl;

cout << "[6] B::ib = " << (int)pVtab[6] << endl;

cout << "[7] B::cb = " << (char)pVtab[7] << endl;

cout << "[8] B2::ib2 = " << (int)pVtab[8] << endl;

cout << "[9] B2::cb2 = " << (char)pVtab[9] << endl;

cout << "[10] D::id = " << (int)pVtab[10] << endl;

cout << "[11] D::cd = " << (char)pVtab[11] << endl;

E序q行l果如下Q?/p>

GCC 3.4.4

VC++ 2003

[0] D::B1::_vptr->

     [0] D::f()

     [1] B::Bf()

     [2] D::f1()

     [3] B1::Bf1()

     [4] D::f2()

     [5] 0x1

[1] B::ib = 0

[2] B::cb = B

[3] B1::ib1 = 11

[4] B1::cb1 = 1

[5] D::B2::_vptr->

     [0] D::f()

     [1] B::Bf()

     [2] D::f2()

     [3] B2::Bf2()

     [4] 0x0

[6] B::ib = 0

[7] B::cb = B

[8] B2::ib2 = 12

[9] B2::cb2 = 2

[10] D::id = 100

[11] D::cd = D

[0] D::B1::_vptr->

     [0] D::f()

     [1] B::Bf()

     [2] D::f1()

     [3] B1::Bf1()

     [4] D::Df()

     [5] 0x00000000

[1] B::ib = 0

[2] B::cb = B

[3] B1::ib1 = 11

[4] B1::cb1 = 1

[5] D::B2::_vptr->

     [0] D::f()

     [1] B::Bf()

     [2] D::f2()

     [3] B2::Bf2()

     [4] 0x00000000

[6] B::ib = 0

[7] B::cb = B

[8] B2::ib2 = 12

[9] B2::cb2 = 2

[10] D::id = 100

[11] D::cd = D

下面是对于子cd例中的虚函数表的图:

我们可以看见Q最端的父cB其成员变量存在于B1和B2中,q被Dl承下M。而在D中,其有B1和B2的实例,于是B的成员在D的实例中存在两䆾Q一份是B1l承而来的,另一份是B2l承而来的。所以,如果我们使用以下语句Q则会生二义性编译错误:

D d;

d.ib = 0; //二义性错?/p>

d.B1::ib = 1; //正确

d.B2::ib = 2; //正确

注意Q上面例E中的最后两条语句存取的是两个变量。虽然我们消除了二义性的~译错误Q但BcdD中还是有两个实例Q这U扉K成了数据的重复Q我们叫q种l承为重复ѝ重复的基类数据成员可能q不是我们想要的。所以,C++引入了虚基类的概c?/p>

ȝ型多重虚拟?/strong>

虚拟l承的出现就是ؓ了解决重复承中多个间接父类的问题的。钻矛_的结构是其最l典的结构。也是我们在q里要讨论的l构Q?/p>

上述?#8220;重复l承”只需要把B1和B2l承B的语法中加上virtual 关键Q就成了虚拟l承Q其l承囑֦下所C:

上图和前面的“重复l承”中的cȝ内部数据和接口都是完全一LQ只是我们采用了虚拟l承Q其省略后的源码如下所C:

class B {……};

class B1 : virtual public B{……};

class B2: virtual public B{……};

class D : public B1, public B2{ …… };

在查看D之前Q我们先看一看单一虚拟l承的情c下面是一D在VC++2003下的试E序Q(因ؓVC++和GCC的内存而局上有一些细节上的不同,所以这里只l出VC++的程序,GCC下的E序大家可以Ҏ我给出的E序自己仿照着写一个去试一试)Q?/p>

int** pVtab = NULL;

Fun pFun = NULL;

 

B1 bb1;

pVtab = (int**)&bb1;

cout << "[0] B1::_vptr->" << endl;

pFun = (Fun)pVtab[0][0];

cout << " [0] ";

pFun(); //B1::f1();

cout << " [1] ";

pFun = (Fun)pVtab[0][1];

pFun(); //B1::bf1();

cout << " [2] ";

cout << pVtab[0][2] << endl;

cout << "[1] = 0x";

cout << (int*)*((int*)(&bb1)+1) <<endl; //B1::ib1

cout << "[2] B1::ib1 = ";

cout << (int)*((int*)(&bb1)+2) <<endl; //B1::ib1

cout << "[3] B1::cb1 = ";

cout << (char)*((int*)(&bb1)+3) << endl; //B1::cb1

cout << "[4] = 0x";

cout << (int*)*((int*)(&bb1)+4) << endl; //NULL

cout << "[5] B::_vptr->" << endl;

pFun = (Fun)pVtab[5][0];

cout << " [0] ";

pFun(); //B1::f();

pFun = (Fun)pVtab[5][1];

cout << " [1] ";

pFun(); //B::Bf();

cout << " [2] ";

cout << "0x" << (Fun)pVtab[5][2] << endl;

cout << "[6] B::ib = ";

cout << (int)*((int*)(&bb1)+6) <<endl; //B::ib

cout << "[7] B::cb = ";

其运行结果如下(我结ZGCC的和VC++2003的对比)Q?/p>

GCC 3.4.4

VC++ 2003

[0] B1::_vptr ->

    [0] : B1::f()

    [1] : B1::f1()

    [2] : B1::Bf1()

    [3] : 0

[1] B1::ib1 : 11

[2] B1::cb1 : 1

[3] B::_vptr ->

    [0] : B1::f()

    [1] : B::Bf()

    [2] : 0

[4] B::ib : 0

[5] B::cb : B

[6] NULL : 0

[0] B1::_vptr->

     [0] B1::f1()

     [1] B1::Bf1()

     [2] 0

[1] = 0x00454310 ç该地址取值后?/span>-4

[2] B1::ib1 = 11

[3] B1::cb1 = 1

[4] = 0x00000000

[5] B::_vptr->

     [0] B1::f()

     [1] B::Bf()

     [2] 0x00000000

[6] B::ib = 0

[7] B::cb = B

q里Q大家可以自己对比一下。关于细节上Q我会在后面一q再说?/p>

下面的测试程序是看子cD的内存布局Q同hVC++ 2003的(因ؓVC++和GCC的内存布局上有一些细节上的不同,而VC++的相对要清楚很多Q所以这里只l出VC++的程序,GCC下的E序大家可以Ҏ我给出的E序自己仿照着写一个去试一试)Q?/p>

D d;

pVtab = (int**)&d;

cout << "[0] D::B1::_vptr->" << endl;

pFun = (Fun)pVtab[0][0];

cout << " [0] "; pFun(); //D::f1();

pFun = (Fun)pVtab[0][1];

cout << " [1] "; pFun(); //B1::Bf1();

pFun = (Fun)pVtab[0][2];

cout << " [2] "; pFun(); //D::Df();

pFun = (Fun)pVtab[0][3];

cout << " [3] ";

cout << pFun << endl;

//cout << pVtab[4][2] << endl;

cout << "[1] = 0x";

cout << (int*)((&dd)+1) <<endl; //????

cout << "[2] B1::ib1 = ";

cout << *((int*)(&dd)+2) <<endl; //B1::ib1

cout << "[3] B1::cb1 = ";

cout << (char)*((int*)(&dd)+3) << endl; //B1::cb1

//---------------------

cout << "[4] D::B2::_vptr->" << endl;

pFun = (Fun)pVtab[4][0];

cout << " [0] "; pFun(); //D::f2();

pFun = (Fun)pVtab[4][1];

cout << " [1] "; pFun(); //B2::Bf2();

pFun = (Fun)pVtab[4][2];

cout << " [2] ";

cout << pFun << endl;

cout << "[5] = 0x";

cout << *((int*)(&dd)+5) << endl; // ???

cout << "[6] B2::ib2 = ";

cout << (int)*((int*)(&dd)+6) <<endl; //B2::ib2

cout << "[7] B2::cb2 = ";

cout << (char)*((int*)(&dd)+7) << endl; //B2::cb2

cout << "[8] D::id = ";

cout << *((int*)(&dd)+8) << endl; //D::id

cout << "[9] D::cd = ";

cout << (char)*((int*)(&dd)+9) << endl;//D::cd

cout << "[10] = 0x";

cout << (int*)*((int*)(&dd)+10) << endl;

//---------------------

cout << "[11] D::B::_vptr->" << endl;

pFun = (Fun)pVtab[11][0];

cout << " [0] "; pFun(); //D::f();

pFun = (Fun)pVtab[11][1];

cout << " [1] "; pFun(); //B::Bf();

pFun = (Fun)pVtab[11][2];

cout << " [2] ";

cout << pFun << endl;

cout << "[12] B::ib = ";

cout << *((int*)(&dd)+12) << endl; //B::ib

cout << "[13] B::cb = ";

cout << (char)*((int*)(&dd)+13) <<endl;//B::cb

下面l出q行后的l果Q分VC++和GCC两部份)

GCC 3.4.4

VC++ 2003

[0] B1::_vptr ->

    [0] : D::f()

    [1] : D::f1()

    [2] : B1::Bf1()

    [3] : D::f2()

    [4] : D::Df()

    [5] : 1

[1] B1::ib1 : 11

[2] B1::cb1 : 1

[3] B2::_vptr ->

    [0] : D::f()

    [1] : D::f2()

    [2] : B2::Bf2()

    [3] : 0

[4] B2::ib2 : 12

[5] B2::cb2 : 2

[6] D::id : 100

[7] D::cd : D

[8] B::_vptr ->

    [0] : D::f()

    [1] : B::Bf()

    [2] : 0

[9] B::ib : 0

[10] B::cb : B

[11] NULL : 0

[0] D::B1::_vptr->

     [0] D::f1()

     [1] B1::Bf1()

     [2] D::Df()

     [3] 00000000

[1] = 0x0013FDC4  ç 该地址取值后?/span>-4

[2] B1::ib1 = 11

[3] B1::cb1 = 1

[4] D::B2::_vptr->

     [0] D::f2()

     [1] B2::Bf2()

     [2] 00000000

[5] = 0x4539260   ç 该地址取值后?/span>-4

[6] B2::ib2 = 12

[7] B2::cb2 = 2

[8] D::id = 100

[9] D::cd = D

[10]  = 0x00000000

[11] D::B::_vptr->

     [0] D::f()

     [1] B::Bf()

     [2] 00000000

[12] B::ib = 0

[13] B::cb = B

关于虚拟l承的运行结果我׃d了(前面的作囑ַl让我生了很严重的厌倦感Q所以就偷个懒了Q大家见谅了Q?/p>

在上面的输出l果中,我用不同的颜色做了一些标明。我们可以看到如下的几点Q?/p>

1Q无论是GCCq是VC++Q除了一些细节上的不同,其大体上的对象布局是一L。也是_先是B1Q黄ԌQ然后是B2Q绿ԌQ接着是DQ灰ԌQ而Bq个类Q青蓝色Q的实例都放在最后的位置?/p>

2Q关于虚函数表,其是第一个虚表,GCC和VC++有很重大的不一栗但仔细看下来,q是VC++的虚表比较清晰和有逻辑性?/p>

3QVC++和GCC都把Bq个类攑ֈ了最后,而VC++有一个NULL分隔W把B和B1和B2的布局分开。GCC则没有?/p>

4QVC++中的内存布局有两个地址我有些不是很明白Q在其中我用U色标出了。取其内Ҏ-4。接道理来说Q这个指针应该是指向Bcd例的内存地址Q这个做法就是ؓ了保证重复的父类只有一个实例的技术)。但取值后却不是。这Ҏ目前qƈ不太清楚Q还向大家请教?/p>

5QGCC的内存布局中在B1和B2中则没有指向B的指针。这点可以理解,~译器可以通过计算B1和B2的size而得出B的偏U量?/p>

l束?/strong>

C++q门语言是一门比较复杂的语言Q对于程序员来说Q我们似乎永q摸不清楚这门语a背着我们在干了什么。需要熟悉这门语aQ我们就必需要了解C++里面的那些东西,需要我们去了解他后面的内存对象。这h们才能真正的了解C++Q从而能够更好的使用C++q门最隄~程语言?/p>

在文章束之前q是介绍一下自己吧。我从事软g研发有十个年头了Q目前是软g开发技术主,技术方面,LUnix/C/C++Q比较喜Ƣ网l上的技术,比如分布式计,|格计算QP2PQAjax{一切和互联|相关的东西。管理方面比较擅长于团队Q技术趋势分析,目理。欢q大家和我交,我的MSN和Email是:haoel@hotmail.com



]]>
Boost.Regex库学习笔?/title><link>http://www.shnenglu.com/tianbianlan/archive/2009/07/24/91015.html</link><dc:creator>天边?/dc:creator><author>天边?/author><pubDate>Fri, 24 Jul 2009 03:48:00 GMT</pubDate><guid>http://www.shnenglu.com/tianbianlan/archive/2009/07/24/91015.html</guid><wfw:comment>http://www.shnenglu.com/tianbianlan/comments/91015.html</wfw:comment><comments>http://www.shnenglu.com/tianbianlan/archive/2009/07/24/91015.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/tianbianlan/comments/commentRss/91015.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/tianbianlan/services/trackbacks/91015.html</trackback:ping><description><![CDATA[     摘要:   在C++~程中,有一点让人挺遗憾的就是C++不支持正则表达式,q让很多用户Z~写支持正则表达式程序而不得不攑ּC++。然而,Boost.Regex库填补了C++在这斚w的空白,它C++很好的支持各U引擎的正则表达式?       l合我的学习Q逐步分析Boost.Regex库?  &nbs...  <a href='http://www.shnenglu.com/tianbianlan/archive/2009/07/24/91015.html'>阅读全文</a><img src ="http://www.shnenglu.com/tianbianlan/aggbug/91015.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/tianbianlan/" target="_blank">天边?/a> 2009-07-24 11:48 <a href="http://www.shnenglu.com/tianbianlan/archive/2009/07/24/91015.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.esfjjr.cn" target="_blank">99ξþþŷƷվ</a>| <a href="http://www.cd-hk.cn" target="_blank">ɫۺϾþ</a>| <a href="http://www.jyyyzxw.cn" target="_blank">պƷþþþþ</a>| <a href="http://www.yzx777.cn" target="_blank">ƷþþþAV</a>| <a href="http://www.y6smog.cn" target="_blank">޹Ʒþþ</a>| <a href="http://www.cjbyt.cn" target="_blank">þþþþþþòҰ߳</a>| <a href="http://www.studenthotel.cn" target="_blank">þùƷ77777</a>| <a href="http://www.cctyn.cn" target="_blank">þþþùƷ۲ӰԺ</a>| <a href="http://www.xingtaiidc.cn" target="_blank">Ů޾Ʒþþۺ</a>| <a href="http://www.kfak.cn" target="_blank">97þóƷ2021</a>| <a href="http://www.zyxslswx.cn" target="_blank">þþþþ˸߳ӰԺ</a>| <a href="http://www.ampul.cn" target="_blank">þþƷһ</a>| <a href="http://www.songyuan163.net.cn" target="_blank">һþaþþƷ</a>| <a href="http://www.cctv-87.cn" target="_blank">ƷþþþӰԺ۲ </a>| <a href="http://www.yaott2.cn" target="_blank">þ޾ƷAV</a>| <a href="http://www.hldqptt.net.cn" target="_blank">þþþùƷ</a>| <a href="http://www.lyfulinmen.com.cn" target="_blank">þþþ99ƷƬԿ</a>| <a href="http://www.denstone.cn" target="_blank">þþƷ72</a>| <a href="http://www.168sf.com.cn" target="_blank">þۺϾɫۺŷݺ</a>| <a href="http://www.effusion.net.cn" target="_blank">ҹƷþþþþapp</a>| <a href="http://www.moonlong.cn" target="_blank">޾ƷþëƬ </a>| <a href="http://www.njisb.cn" target="_blank">þþùƷ</a>| <a href="http://www.node-js.cn" target="_blank">˾þˬ</a>| <a href="http://www.xfshebao.cn" target="_blank">ۺϾþøϾþúݺݺ97ɫ</a>| <a href="http://www.syyinuo.cn" target="_blank">޹˾þۺ3d</a>| <a href="http://www.kanglue.cn" target="_blank">þþþAVۿ</a>| <a href="http://www.luben8151998.cn" target="_blank">Ʒþþþþҹҹ</a>| <a href="http://www.novagroup.com.cn" target="_blank">ɫþþ99Ʒ91</a>| <a href="http://www.ofuax.cn" target="_blank">þþþþAvӰԺ</a>| <a href="http://www.skjzy.cn" target="_blank">þþƷˬӰ</a>| <a href="http://www.dowee.com.cn" target="_blank">ƷþþĻһ</a>| <a href="http://www.sdmtsk.cn" target="_blank">ŷ龫Ʒþþþþ</a>| <a href="http://www.zenavo.cn" target="_blank">þˬˬƬav鷳</a>| <a href="http://www.angfei.com.cn" target="_blank">ŮһaëƬþw</a>| <a href="http://www.oubaidu.cn" target="_blank">þ˾Ʒԭձ</a>| <a href="http://www.henpu.cn" target="_blank">Ʒ91þþþþþa</a>| <a href="http://www.sj-gd.cn" target="_blank">ݺݾƷþþĻ</a>| <a href="http://www.niguoyi.cn" target="_blank">Ʒһþ</a>| <a href="http://www.love20.com.cn" target="_blank">˺ݺۺϾþ88</a>| <a href="http://www.haokan1.cn" target="_blank">þۺϾɫۺ97_þþ</a>| <a href="http://www.liaojiaren.cn" target="_blank">ձþ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>