仿函数(function object,函数对象)

2016/01/12

引子

前一篇文章讲到了C++11的新特性lambda表达式

lambda表达式的本质是什么呢?为探究这个问题,我们将一段写有lambda表达式的代码反编译,可能会发现一些秘密.

首先写段程序:

在调试该代码时我们打开汇编视图,发现如下代码:

其中 <$_0::operator()(int, int) const>      即对应原代码中的lambda表达式。这里一串重载了"()"(operator())操作符的代码,即本文将要了解的仿函数

Note:  此处的 const  ,也应证了前文 mutable 可变范围 中提到的,lambda的调用运算符为"const-by-value"的

  定义

仿函数(finctor)是一种早期的叫法,在C++11中,标准的叫法为函数对象(function object)。仿函数是一种行为类似函数、具有函数特性的对象。

仿函数是一个对象,而不是函数。仿函数的类通过重载函数操作符"()"(operator())来实现函数调用的特性。

通过下面的例子来简单说明如何使用仿函数

这个例子中,lineA声明了一个对象。这是一个函数对象,其类(结构)定义在functional文件中,是STL内置的模板类。该类用于比较两个参数的大小。

lineB则像函数一样直接给该对象传入两个参数。

lineC是另一种写法。greater<int>() 声明了一个临时对象,然后传入参数(3,4)调用该临时对象。这种写法往往比lineB更加简洁。在STL源码里大量使用了这种写法。

lineD则是使用自定义的函数对象。

Note:lineB中使用了boolalpha,是iostream提供的一个操作符,这将使此后的标准输出中,将bool值输出为"true"或"false",而不是1/0。于其相反的操作为noboolalpha.

继续阅读

Coding 6,965

lambda 表达式

2016/01/11

LAMBDA简介lambda

从C++11开始,c++开始支持lambda表达式。

lambda用来创建一个可以捕获作用域内变量的匿名函数对象的闭包。这通常用来封装传递给算法或异步方法的少量代码块。

例如,简单实现一个Trim函数,去除字符串里的空格:

此例中,

即是一个lambda表达式。其做为一个匿名函数,被算法  for_each 使用,使得代码更简洁。

继续阅读

Coding 7,431

使用 RasterIO 读取影像

2015/06/20

gdalbaner当我们使用 GDAL  从栅格数据(RasterData)影像中读写数据的时候,我们最常使用的方法就是 RasterIO。 GDAL 在 GDALDataset 类和 GDALRasterBand 类中都提供了 RasterIO 方法。在这两个类中,RasterIO 函数的差别不大。下面我们通过一个实例来具体了解如何使用 RasterIO

 原型

在 GDALDataset 中,RasterIO  方法的定义如下:

下面我们来了解各个参数的意义:

eRWFlag
它用来指示 RasterIO 的操作方式,读,还是写。GDALRWFlag 枚举有两个值, GF_Read = 0 为读取数据, GF_Write = 1  为写数据。

nXOff,nYOff
它用来指示 RasterIO 在影像上操作(读或写)范围的起始坐标。在影像中,左上角的坐标为 (0,0)。

nXSize,nYSize
它用来指示 RasterIO 在影像上操作范围的大小。nXSize为宽,nYSize为高。 它以 (nXOff,nYOff)为起点,决定了操作影像的范围的大小。

pData
这是一个指针,指向缓存数据块。如果 eRWFlag 为 GF_Write,函数会将 pData 中的数据写入影像,如果为 GF_Read, 那么函数会将从影像中取得的数据写入到 pData 中。 pData 为 void* 类型,它真实的数据类型将由参数 eBufType 决定。
由于 pData 为 void* 类型,所以它的大小一般使用 字节(byte) 来作单位。它的大小需要最底满足缓冲区的大小。即 缓冲区内存块大小 = 缓冲区长 X 缓冲区宽 X 波段数 X 每波段数据元大小 。用参数来表示:

nBufXSize,nBufYSize
它用来指定缓冲区的宽高。这两个参数配合 nXSize,nYSize 来实现对影像的缩放。例如,如果 nBufXSize > nXSize,即缓存区宽度比影像操作区宽度大,那么读取数据时,将得到一个在 X 方向放大的缓冲数据。反之则得到缩小的缓冲数据。
值得注意的是,在读取并缩小影像时,GDAL 将自动分析金字塔(Overviews)中数据,选取合适的金字塔层来来读取数据。所以建立合适的金字塔,对读取影像的效率的很大帮助。

eBufType
它也是一个枚举,用来指示操作的数据类型。如果它与 GDALRasterBand 的数据类型不一致,则 RasterIO 将会做类型转换。需要注意的是,将数据从较大的单位向较小的单位进行转换时,RasterIO 会将数据截取而不是比例缩小。例如从 GDT_Int16(Thirty two bit unsigned integer)转为 GDT_Byte(Eight bit unsigned integer)时,超出 255 的部分将会被直接丢弃。

nBandCount,panBandMap
nBandCount为要操作的波段数。panBandMap则为读写的波段的顺序,即我们可以先读取哪一个波段,后读取哪一个波段。它是一个 int 型数组,内容为波段编号,大小为 nBandCount。这个参数可以为 NULL,这样将默认顺序使用影像的前 nBandCount 个波段来读写。需要注意的是,波段编号是从 1 开始的。 继续阅读

Coding 8,678

GitHub 设置代理

2015/06/16

红杏老板带吃喝嫖赌欠下……也不知道多少钱,带着他的小姨子跑了……所以,以下部分不用看了。再见。

 

运营商对GitHub的封锁使很多开发者感到头疼。幸好,我们还有VPN.

本文介绍如何结合红杏VPN公益版使用GitHub 。

红杏和(fān)谐(qiáng),想必大家在和GFW做斗争的时候都已经很熟悉了。做为一款和谐插件,红杏还是比较可靠的,收费也比较便宜。但是有一点比较难以接受的是,它无法给其他软件提供代理。为了弥补这个问题,红杏推出了一个公益版本,给广大开发者提供了一个免费的VPN服务器地址:

http://hx.gy:1080

在此次过程中,我们使用的就是这个地址。

git提供如下命令允许用户配置代理: 继续阅读

Note 7,190

Sqlite3 写入数据库失败:attempt to write a readonly database.

2015/05/24

问题及解决办法

一个Android程序在大部分手机上运行正常,在某一款手机(华为荣耀7)上运行失败。具体表现为在写入Sqlite数据库时出现Sqlite3Exception :attempt to write a readonly database.

在仔细检查sqlite3_open/sqlite3_open_v2的参数、apk的SD卡读取权限、sqlite数据库的文件读写权限后,并没有发现任何问题,那么分析问题可能出在NDK与机器架构上了。

查看该机器使用的是arm64位CPU.然而在application.mk文件里,APP_ABI 并未配置64位选项。

配置

 APP_ABI   := armeabi-v7a arm64-v8a

后再使用NDK编译 ,解决sqlite3的Readonly的问题。

 

 

Note 7,989

树莓派 + DHT11 获取温度与湿度

2015/05/12

§§ DHT11介绍

DHT11是一款含有已校准数字信号输出的温湿度复合传感器。包括一个电阻式感湿元件和一个NTC测温元件,可与8位单片机相连接。是一款广泛使用是电子元器件。DHT11的一般形态如下图:

DHT11采用四PIN引bKKNC脚。

  • 引脚1:VCC.  接入3~5.5V直流电源。
  • 引脚2:Data.  串行数据总线
  • 引脚3:N/A.  空引脚
  • 引脚4:GND.  接地线

DHT11的供电电压为 3-5.5V。传感器上电后,要等待 1s 以越过不稳定状态.电源引脚(VDD,GND)之间可增加一个100nF 的电容,用以去耦滤波。

串行数据总线用于和单片机进行数据通讯和同步。一次通信时间在4ms左右,传输40bit数据,高位先出。数据协议8位为一组,由高至底分别为:

  • 8bit  湿度整数部分
  • 8bit  湿度小数部分
  • 8bit  温度整数部分
  • 8bit  温度小数部分
  • 8bit  检验和

dht11_data

 

继续阅读

Coding 7,474

SQLite API

2015/04/05

SQLiteAPI从功能上可以分为两部分:核心API和扩展API.
核心API用于提供基本的数据库操作,如连接数据库、处理SQL、查询结果,以及一些辅助函数如字符串格式化、调试、错误处理等。
扩展API支持用户自定义函数、聚合和排序规则。

主要数据结构

QLite有很多组件。从程序员的角度 ,我们要了解的主要有connection、statement、B-tree、pager。

SQLite-CAPI-Modle

 

connection 和 statement

API 中,与查询处理有关的两个基本数据结构是连接和语句。在 C-API 中,它们分别对应 sqlite3 和 sqlitestmt 句柄。基本上,所有主要 API 都是在操作这两个数据结构。
一个连接对象(connection)代表数据库的连接和事务的上下文。statement来自于connection, 每个statement都有一个connection。 一个statement代表了一个编译的SQL语句。在内部,它使用VDBE来表示。statement 包括了执行一个命令所需要的一切。

B-tree 和 Pager

一个连接对象可以连接到多个数据库对象——一个主数据库和多个附加数据库。每个数据库对象都有一个B-Tree和相应的Pager对象。SQLite数据库中使用B-tree来存储表的索引和数据。statement使用B-tree的游标遍历存储在page中的记录。B-tree不直接读写磁盘,它只维护page间的关系。在游标访问page之前,pager负责将数据从磁盘中加载到页面缓存(page cache)中。
B-tree 中的页面由B-tree记录组成,也叫payloads。每个payload分两个域:关键字域(key field)或数据域(data field)。关键字域是ROWID或其它关键字的值。B-tree的任务是排序和遍历,所以关键字对其尤为重要。 如果cursor改变了page,为防止事务回滚,则pager需要保存修改前的page。

Coding 2,888

SQLite体系结构

2015/03/30

sqlite采用模块化的体系结构,可划分为3个子系统共8个模块,这些模块将查询过程分成独立的任务,像流水线一样工作。

Sqlite 体系结构

接口

接口处于Sqlite查询工作流的起始位置,由Sqlite C API构成。应用程序由此处与Sqlite交互。

编译器

编译过程由词法分析器(Tokenizer)、语法分析器(Parser)开始,协同处理文本形式的结构化查询语句(SQL),分析其语法的有效性,然后转化为下一层能方便处理的层次化数据结构。SQL语句先被分解成一个个的词法记号,然后以语法树的形式重组,语法分析器将该树传给代码生成器。
代码生成器将语法树翻译成一种Sqlite专用的汇编代码,这些代码由一些虚拟机招待的指令组成。代码生成器的唯一工作是将语法树转换为完全由这种汇编代码编写的程序并交给虚拟机处理。

虚拟机

Sqlite架构的核心是虚拟机,也称做虚拟数据库引擎(Virtual Database Engine,VDBE)。它是基于寄存器的虚拟机,在字节码(称为虚拟机语言)上工作,使得它可以独立于操作系统、CPU和系统体系结构。虚拟机语言由100多个被称为操作码(opcodes)的任务构成。VDBE是一个专为数据处理设计的虚拟机,它的指令集中所有的指令,或者用来完成具体的数据库操作(如打开一个表的游标、开始一个事务),或者以某种方式控制栈完成这些操作做准备。这些指令以恰当的顺序组合,就可以满足复杂的SQL命令的要求。
VDBE之前的所有模块都是用于创建VDBE程序,它之后的所有模块都是用于执行VDBE程序。

后端

后端由B-Tree、页缓存(Page cache)以及操作系统接口组成。 B-Tre的职责是排序。它维护着多个页面之间的复杂关系,这些关系能保证快速定位并找到一个有联系的数据。B-Tree将页面组织成树状结构,页面是树的叶子。这些结构便于搜索。 Pager帮助B-Tree管理页面,它负责传输。pager根据B-Tree的请求从磁盘读取页面,或向磁盘写入页面。由于磁盘操作的性能有限,pager试图通过将频繁使用的页面缓存到内存中来进行加速。pager的功能还包括事务管理、数据库锁以及崩溃恢复,其中许多功能是通过OS接口实现的。
操作系统掊向上层屏蔽了不同操作系统间的差异。保证了其他模块代码的整洁,将凌乱的操作在一个地方集中管理起来,使得Sqlite可以很容易的移植到不同的操作系统上。

Coding 7,275