C++ Built-In Array 的语义
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]; //line1:test 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]; //line2:test 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; //line3:test 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试图创建带有destructor的StackObject2类的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 array对class object的支持是十分重要的语言构造,它是C++把class object和原始变量同样对待的又一反映,它大大增加了C++的附加值。
然而我们一如既往,需要对C++这一语言构造的语义深入了解。以便正确使用C++ built-in array。
C++ Built-In Array 的语义的更多相关文章
- [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 ...
- C# to IL 12 Arrays(数组)
An array is a contiguous block of memory that stores values of the same type. These valuesare an ind ...
- Drupal Module Hooks
Drupal is a Content Management System. Drupal is also deeply, deeply weird. While systems like Magen ...
- SparkStreaming实现Exactly-Once语义
作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 转载请注明出处 译自:http://blog.cloudera.com/blog/2015/03/exactly ...
- C#开发微信门户及应用(31)--微信语义理解接口的实现和处理
微信语义理解接口提供从用户自然语言输入到结构化解析的技术实现,使用先进的自然语言处理技术给开发者提供一站式的语义解析方案.该平台覆盖多个垂直领域的语义场景,部分领域还可以支持取得最终的展示结果.开发者 ...
- 如何让你的JavaScript代码更加语义化
语义化这个词在 HTML 中用的比较多,即根据内容的结构化选择合适的标签.其作用不容小觑: 赋予标签含义,让代码结构更加清晰,虽然我们可以在标签上添加 class 来标识,但这种通过属性来表示本体的形 ...
- JavaScript Array 常用函数整理
按字母顺序整理 索引 Array.prototype.concat() Array.prototype.filter() Array.prototype.indexOf() Array.prototy ...
- Array类
class Array Arrays are ordered, integer-indexed collections of any object. Array indexing starts at ...
- caffe初步实践---------使用训练好的模型完成语义分割任务
caffe刚刚安装配置结束,乘热打铁! (一)环境准备 前面我有两篇文章写到caffe的搭建,第一篇cpu only ,第二篇是在服务器上搭建的,其中第二篇因为硬件环境更佳我们的步骤稍显复杂.其实,第 ...
随机推荐
- 利用js制作html table分页示例(js实现分页)
有时候table的列数太长,不利于使用者查询,所以利用JS做了一个table的分页,以下为相关代码 一.JS代码 <script type="text/javascript" ...
- Git基本操作(Windows下)
在开始使用Git之前,我觉得是很有必要了解下Git与其他版本控制系统的差异与文件在Git中的三种状态.可以到下面这个网站看下:Git详解之一 Git起步,了解之后,可以对Git的基本操作有一个更清晰的 ...
- CodeForce 7 B - Memory Manager(模拟)
题目大意:给你一段内存,要你进行如下的三个操作. 1.分配内存 alloc X ,分配连续一段长度为X的内存. 如果内存不够应该输出NULL,如果内存够就给这段内存标记一个编号. 2.擦除编号为 ...
- 3C Tic-tac-toe
题目大意: 两个选手轮流在 3*3的矩阵上作标记,一个选手总是画一个‘X’, 另一个选手总是画一个‘0’,谁先在水平线上或者垂直线上,或者对角线上,先完成三个点连在一块,谁就赢.画‘×’的选手是第一个 ...
- 数据结构(Splay平衡树):HAOI2008 排名系统
[HAOI2008] 排名系统 [题目描述] 排名系统通常要应付三种请求:上传一条新的得分记录.查询某个玩家的当前排名以及返回某个区段内的排名记录.当某个玩家上传自己最新的得分记录时,他原有的得分记录 ...
- HDOJ(HDU) 2156 分数矩阵(嗯、求和)
Problem Description 我们定义如下矩阵: 1/1 1/2 1/3 1/2 1/1 1/2 1/3 1/2 1/1 矩阵对角线上的元素始终是1/1,对角线两边分数的分母逐个递增. 请求 ...
- DFS hdu 1016
http://acm.hdu.edu.cn/showproblem.php?pid=1016 #include <iostream> using namespace std; int a[ ...
- Jenkins 一: 环境安装以及配置
安装JDK 下载地址: http://www.oracle.com/technetwork/java/javase/downloads/index.html 选择的JDK版本和开发使用的JDK版本最好 ...
- 布隆过滤器的java实现
package com.kaikeba.data.jobspider.util; import java.util.BitSet; public class Bloomfilter { private ...
- ubuntu忘记密码
Do these two things just to make sure: mount -o remount,rw / This first part remounts the root parti ...