C++ 编译花了大量精力使得class和原始类(primitive types)的用法一致。比如array的应用:

A a[100];// A is class

int b[100]

虽然a是用户定义的类的对象,但是用起来与整数型的array相比并无差别。我们现在看看语义上的差别。

A 是POD类(完全具有值语义的类)

如果A是具有值语义的POD(参见我关于值语义的博客:http://www.cnblogs.com/ly8838/p/3929025.html ),测试显示A 的创建和读写与一般变量没有任何差别,当然性能也不会有差别。

也就是说,A a[3] ;和 A a1, a2,a3 在语义上完全一样,也没有丝毫性能上的区别。

A 是有默认的构造函数(但没有destructor)的类

我们有一个简单的struct

struct StackObject

{

int _a;

int _b;

StackObject(): _a(0), _b(1)

{

}

};

和简单的测试函数:

void TestArraySemantics()

{

StackObject sa[10]; //line 1:call vector constructor iterator

sa[0]._a= 1;

sa[9]._b = 10;

}

在VC++2010中运行时,我们看到line1调用了编译自生的函数。这是一个通用的“矩阵构造循环(vector constructor iterator)”:

它的大致实施如下:

void Vector_constructor_iterator(

int array_size,

int array_element_size,

void (*Ctr)(void *addr),

char *arrayStartAddress)

{

      for(int i = 0; i < array_size; ++i)

      {

            void *objAddr = arrayStartAddress + i * array_element_size;

            Ctr(objAddr);

      }

}

这是一个典型的 C 函数,它将 StackObject 的构造函数作为函数指针进行调用。

从这个函数来看,它使得A a[3]A a1,a2, a3 的语义发生了根本变化。我们不但要调用编译产生的函数,还要用指针间接地调用StackObject的构造函数。测试结果显示,用array比不用array的“构造”速度大约下降30%。考虑到array的应用价值,这个速度的下降是可以理解和接受的。

A 是有默认构造函数以及destructor的类

加了destructor后,A a[10] 的语义又有了新的变化。如果读了我的上篇关于异常处理的博客(http://www.cnblogs.com/ly8838/p/3961119.html )可知:编译必须保证所有创建的object“全部”被摧毁,所以它必须“记住”创建过程中的热点。

我们加另一个dummy 类,来测试destructor对array 的影响:

struct StackObject2

{

       int _a;

       int _b;

       StackObject2(): _a(0), _b(1)

       {

       }

       ~StackObject2()

       {

             _a = _b = 0;

       }

};

我们的测试函数改为

void TestArraySemantics()

       {

             clock_t begin = clock();

             for (int i = 0; i < 100000; ++i)

             {           

                    StackObject sa[3]; //line1test without d’tr

                    sa[0]._a= 1;

                    sa[1]._b = 2;

                    sa[2]._b = 3;

             }

             clock_t end = clock();

             auto spent = double(end - begin) / CLOCKS_PER_SEC;

             printf("spent for 'array' is %f\n", spent);

 

             begin = clock();

             for (int i = 0; i < 100000; ++i)

             {           

                    StackObject2 sa[3]; //line2test with d’tr

                    sa[0]._a= 1;

                    sa[1]._b = 2;

                    sa[2]._b = 3;

             }

            end = clock();

             spent = double(end - begin) / CLOCKS_PER_SEC;

             printf("spent for 'array with dtro' is %f\n", spent);

 

             begin = clock();

             for (int i = 0; i < 100090; ++i)

             {           

                    StackObject sa1, sa2, sa3; //line3test without array

                    sa1._a= 1;

                    sa2._b = 2;

                    sa3._b = 3;

             }

           end = clock();

           spent = double(end - begin) / CLOCKS_PER_SEC;

             printf("spent for 'none-array' is %f\n", spent);

            

       }

 

上面的line2试图创建带有destructorStackObject2类的array. 在VC++,我们注意到这时编译产生另一名字稍稍不同的函数“eh vector constructor iterator”,然而察看生成的代码,发现它和vector constructor iterator大大不同了。它的伪码大致如此:

void Vector_constructor_iterator_with_dtor(

             int array_size,

             int array_element_size,

             void (*Ctr)(void *addr),

             void (*Dtr)(void *addr),

             char *arrayStartAddress)

       {

             int lastCreated = -1;

             try

             {

                     for(int i = 0; i < array_size; ++i)

                     {

                           void *objAddr = arrayStartAddress + i * array_element_size;

                           Ctr(objAddr);

                           lastCreated = i;

                     }

              }

              catch(...)

              {

                    // destroy partially created array in case or fault

                    for(int i = 0; i <= lastCreated; ++i)

                    {

                      void *objAddr = arrayStartAddress + i * array_element_size;

                      Dtr (objAddr);

                    }

             }

       }

比较伪码我们看出:Vector_constructor_iterator_with_dtor 和 Vector_constructor_iterator 的主要区别是增加了异常处理的机制,用来销毁“已经构造”的矩阵元素。

运行 TestArraySemantics 表明,带有destructor的类的array构造速度下降了近 300%

所以,去除不必要的destructor的重要性又一次充分体现。

结论

C++ built-in arrayclass object的支持是十分重要的语言构造,它是C++把class object和原始变量同样对待的又一反映,它大大增加了C++的附加值。

然而我们一如既往,需要对C++这一语言构造的语义深入了解。以便正确使用C++ built-in array

C++ Built-In Array 的语义的更多相关文章

  1. [JavaScript] Array.prototype.reduce in JavaScript by example

    Let's take a closer look at using Javascript's built in Array reduce function. Reduce is deceptively ...

  2. C# to IL 12 Arrays(数组)

    An array is a contiguous block of memory that stores values of the same type. These valuesare an ind ...

  3. Drupal Module Hooks

    Drupal is a Content Management System. Drupal is also deeply, deeply weird. While systems like Magen ...

  4. SparkStreaming实现Exactly-Once语义

    作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 译自:http://blog.cloudera.com/blog/2015/03/exactly ...

  5. C#开发微信门户及应用(31)--微信语义理解接口的实现和处理

    微信语义理解接口提供从用户自然语言输入到结构化解析的技术实现,使用先进的自然语言处理技术给开发者提供一站式的语义解析方案.该平台覆盖多个垂直领域的语义场景,部分领域还可以支持取得最终的展示结果.开发者 ...

  6. 如何让你的JavaScript代码更加语义化

    语义化这个词在 HTML 中用的比较多,即根据内容的结构化选择合适的标签.其作用不容小觑: 赋予标签含义,让代码结构更加清晰,虽然我们可以在标签上添加 class 来标识,但这种通过属性来表示本体的形 ...

  7. JavaScript Array 常用函数整理

    按字母顺序整理 索引 Array.prototype.concat() Array.prototype.filter() Array.prototype.indexOf() Array.prototy ...

  8. Array类

    class Array Arrays are ordered, integer-indexed collections of any object. Array indexing starts at ...

  9. caffe初步实践---------使用训练好的模型完成语义分割任务

    caffe刚刚安装配置结束,乘热打铁! (一)环境准备 前面我有两篇文章写到caffe的搭建,第一篇cpu only ,第二篇是在服务器上搭建的,其中第二篇因为硬件环境更佳我们的步骤稍显复杂.其实,第 ...

随机推荐

  1. node.js基础模块http、网页分析工具cherrio实现爬虫

    node.js基础模块http.网页分析工具cherrio实现爬虫 一.前言      说是爬虫初探,其实并没有用到爬虫相关第三方类库,主要用了node.js基础模块http.网页分析工具cherri ...

  2. Squares(哈希)

    Time Limit: 3500MS   Memory Limit: 65536K Total Submissions: 14328   Accepted: 5393 Description A sq ...

  3. C语言基础课程 第二课 HelloWorld不为菜鸟所知的秘密

    1    愉快的开端hello world    4 1.1    include头文件包含    4 1.2    main函数    4 1.3    注释    4 1.4    {}括号,程序 ...

  4. 解决weblogic Managed Server启动非常慢的情况

    jdk版本:1.7.0_79 查看控制台日志停留在如下地方: . . JAVA Memory arguments: -Xms2048m -Xmx4096m -XX:MaxPermSize=512m . ...

  5. 数学(组合,容斥):COGS 1220. 盒子与球

    1220. 盒子与球 ★   输入文件:boxball.in   输出文件:boxball.out   简单对比 时间限制:1 s   内存限制:128 MB [问题描述] 现有r个互不相同的盒子和n ...

  6. 【动态规划】Vijos P1493 传纸条(NOIP2008提高组第三题)

    题目链接: https://vijos.org/p/1493 题目大意: 二取方格数,从(1,1)向下或向右走到(n,m)走两次,每个走到的格子值只能被取一次所能取到的最大值. (n,m<=50 ...

  7. C# 匿名方法 委托 Action委托 Delegate委托

    原文地址:https://msdn.microsoft.com/zh-cn/library/bb882516.aspx 匿名函数是一个“内联”语句或表达式,可在需要委托类型的任何地方使用. 可以使用匿 ...

  8. Mac下Intellij IDea发布Java Web项目(适合第一次配置Tomcat的家伙们)详解二

    准备工作:新建第一个JavaWeb项目 step3 给第一次配置tomcat的家伙们再说一遍如何配置tomcat 3.1 [Run]-[Edit Configurations] 3.2 [Defaul ...

  9. 怎样把redis编译为库,挪为己用?

    其实这是个伪命题.因为只要正常编译redis,那么在 /deps/hiredis/ 目录下就会生成动态库文件 libhiredis.so. 为了便于学习redis源码,编写一些测试程序,并进行单步跟踪 ...

  10. Event 元标签中的代码提示问题

    自定的事件可以利用Event元标签在支持该事件的类里面做绑定,绑定后FlashBuilder会有代码提示,以提示该类支持的事件类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 ...