GDAL矢量数据集相关接口的资源控制问题
1. 引言
笔者在《使用GDAL读写矢量文件》这篇文章中总结了通过GDAL读写矢量的具体实现。不过这篇文章中并没有谈到涉及到矢量数据集相关接口的资源控制问题。具体来说,GDAL/OGR诞生的年代连C++语言本身都不是很完善(c++11之前),因此提供的C++接口往往存在申请的资源需要释放的问题,因此在这里将其总结一下。
2. 详论
2.1 数据集类GDALDataset
矢量数据集GDALDataset对象需要通过GDALOpenEx来读取或者更新。在不需要这个对象之后,使用GDALClose进行关闭。例如:
GDALDataset *poDS = (GDALDataset*)GDALOpenEx(filePath, GDAL_OF_VECTOR, NULL, NULL, NULL);
//...
GDALClose(poDS);
poDS = nullptr;
另一方面,通过驱动类GDALDriver创建矢量数据集,不需要之后仍然使用GDALClose进行关闭。例如:
GDALDriver* driver = GetGDALDriverManager()->GetDriverByName("ESRI Shapefile");
if (!driver)
{
printf("Get Driver ESRI Shapefile Error!\n");
return false;
}
GDALDataset* dataset = driver->Create(filePath, 0, 0, 0, GDT_Unknown, NULL);
GDALClose(dataset);
dataset = nullptr;
理论上来说,GDALDataset对象在打开或者创建之后,使用delete进行释放也是可以的。但是一般而言,最好使用GDAL本身提供出来的释放接口。因为这个接口的内部实现可能并不只是delete那么简单,可能有其他的资源释放操作。不仅仅是GDAL,其他类库也是同理。
2.2 图层类OGRLayer
GDALDataset既可以是矢量数据集,也可以是栅格数据集。但是只有矢量数据集才能获取或创建图层类OGRLayer。但是无论是获取还是创建OGRLayer,再无需使用之后,都不用再进行主动释放了,OGRLayer对象会被GDALDataset对象托管,在GDALClose释放数据集对象之后,图层类OGRLayer就会随之释放。
OGRLayer* poLayer = poDS->GetLayer(0);
//获取后无需显式释放OGRLayer
OGRLayer* poLayer = dataset->CreateLayer("houseType", NULL, wkbPolygon, NULL);
//创建后无需显式释放OGRLayer
2.3 要素类OGRFeature
要素类OGRFeature一般从图层类OGRLayer对象中获取或者创建,不过无论是获取还是创建都需要进行显式释放。例如读取矢量数据集时遍历获取要素:
OGRFeature *poFeature;
while ((poFeature = poLayer->GetNextFeature()) != NULL)
{
OGRGeometry *pGeo = poFeature->GetGeometryRef();
//...
OGRFeature::DestroyFeature(poFeature);
}
这里的OGRFeature::DestroyFeature(poFeature);就是GDAL提供的用于销毁要素对象的方法。另一方面,如果是写出数据集创建要素,比如笔者这里创建一个经纬度网格的矢量:
for (int yi = -90; yi < 90; ++yi) {
for (int xi = -180; xi < 180; ++xi) {
OGRFeature poFeature(poLayer->GetLayerDefn());
OGRLinearRing ogrRing;
ogrRing.addPoint(xi, yi);
ogrRing.addPoint(xi + 1, yi);
ogrRing.addPoint(xi + 1, yi + 1);
ogrRing.addPoint(xi, yi + 1);
ogrRing.closeRings();
OGRPolygon polygon;
polygon.addRing(&ogrRing);
poFeature.SetGeometry(&polygon);
if (poLayer->CreateFeature(&poFeature) != OGRERR_NONE) {
printf("Failed to create feature in shapefile.\n");
return false;
}
}
}
OGRFeature使用的是值对象,在超出作用域之后会自动销毁。经过验证笔者这样写并没有问题,可以推断OGRLayer对于OGRFeature对象的管理应该是采用的深拷贝方式,并且会托管这个拷贝后的OGRFeature对象。
2.4 几何类OGRGeometry
几何类OGRGeometry使用了C++类的继承和多态特性,本身其是一个基类,但是继承出了如OGRLinearRing、OGRPolygon等子类来表达点线面多种要素几何类型。因此GDAL提供了一个工厂类来创建和销毁,这是一种非常经典的设计模式:
OGRGeometry* poGeom = OGRGeometryFactory::createGeometry(wkbPoint);
// 使用完 poGeom 后释放它
OGRGeometryFactory::destroyGeometry(poGeom);
也就是OGRGeometryFactory::createGeometry和OGRGeometryFactory::destroyGeometry需要成对出现。不过笔者认为如果不是为了多态表达,直接使用值对象更加方便,如第2.3节中的示例所示。
另外,OGRGeometry对象是需要放置到OGRFeature对象中的,因此OGRFeature提供了两个接口:
OGRErr SetGeometryDirectly(OGRGeometry*):浅拷贝OGRGeometry对象,OGRFeature对象直接托管OGRGeometry对象的所有权。OGRErr SetGeometry(const OGRGeometry*):深拷贝OGRGeometry对象,OGRFeature对象托管OGRGeometry拷贝对象的所有权。
另外,几何类之间的相互引用也是如此,如第2.3节中的示例所示,多边形增加环也有两个接口:
addRingDirectly()浅拷贝OGRLinearRing对象,OGRPolygon对象直接托管OGRLinearRing对象的所有权。addRing()深拷贝OGRLinearRing对象,OGRPolygon对象托管OGRLinearRing拷贝对象的所有权。
也就是一般而言,GDAL通常使用Directly后缀的函数接口来表达对原几何对象的托管。
3. 其他
可以看到,GDAL的资源控制方面还是有点混乱的,有的要显式释放,有的又可以托管,有的干脆提供了两个接口。据说新的GDAL版本引入了很多新的C++特性,估计资源控制的逻辑要清晰一点。另外,我们也可以主动使用一些新的C++特性来避免资源控制需要主动释放的问题。例如使用智能指针,配合自定义删除器来销毁OGRFeature对象,如下例所示:
// 获取第一个图层
OGRLayer* poLayer = poDS->GetLayer(0);
if (poLayer == nullptr) {
std::cerr << "Failed to get the layer." << std::endl;
GDALClose(poDS);
return -1;
}
// 自定义删除器用于销毁 OGRFeature
auto featureDeleter = [](OGRFeature* poFeature) {
OGRFeature::DestroyFeature(poFeature);
};
// 遍历图层中的要素
poLayer->ResetReading();
std::unique_ptr<OGRFeature, decltype(featureDeleter)> poFeature(nullptr, featureDeleter);
while ((poFeature.reset(poLayer->GetNextFeature())), poFeature) {
// 获取几何体
OGRGeometry* poGeometry = poFeature->GetGeometryRef();
if (poGeometry != nullptr) {
// 输出几何体的WKT表示
char* pszWKT = nullptr;
poGeometry->exportToWkt(&pszWKT);
std::cout << "Geometry: " << pszWKT << std::endl;
CPLFree(pszWKT); // 释放WKT字符串
}
}
GDAL矢量数据集相关接口的资源控制问题的更多相关文章
- Linux资源控制-CPU和内存
主要介绍Linux下, 如果对进程的CPU和内存资源的使用情况进行控制的方法. CPU资源控制 每个进程能够占用CPU多长时间, 什么时候能够占用CPU是和系统的调度密切相关的. Linux系统中有多 ...
- Linux资源控制-CPU和内存【转】
转自:http://www.cnblogs.com/wang_yb/p/3942208.html 主要介绍Linux下, 如果对进程的CPU和内存资源的使用情况进行控制的方法. CPU资源控制 每个进 ...
- C#+AE实现类似IDentify功能及对高亮显示相关接口的总结
kenika 原文C#+AE实现类似IDentify功能及对高亮显示相关接口的总结 ArcMap中的Identify功能是有目的查看要素(Feature)属性信息经常使用的工具.ArcMap中的Ide ...
- C#开发微信门户及应用(42)--使用Autofac实现微信接口处理的控制反转处理
在很多情况下,我们利用IOC控制反转可以很方便实现一些接口的适配处理,可以在需要的时候切换不同的接口实现,使用这种方式在调用的时候,只需要知道相应的接口接口,具体调用哪个实现类,可以在配置文件中动态指 ...
- Spring中Aware相关接口原理
Spring中提供一些Aware相关接口,像是BeanFactoryAware. ApplicationContextAware.ResourceLoaderAware.ServletContextA ...
- Servlet相关接口和Servlet的生命周期
http://www.cnblogs.com/luotaoyeah/p/3860292.html Servlet相关接口和Servlet的生命周期 创建一个Servlet类最直接的方式是实现javax ...
- 【Spring源码分析系列】ApplicationContext 相关接口架构分析
[原创文章,转载请注明出处][本文地址]http://www.cnblogs.com/zffenger/p/5813470.html 在使用Spring的时候,我们经常需要先得到一个Applicati ...
- Identity4实现服务端+api资源控制+客户端请求
准备写一些关于Identity4相关的东西,最近也比较对这方面感兴趣.所有做个开篇笔记记录一下,以便督促自己下一个技术方案方向 已经写好的入门级别Identity4的服务+api资源访问控制和简单的客 ...
- 5.cgroup资源控制
控制组( CGroups)是 Linux 内核的一个特性,主要用来对共享资源进行隔离.限制.审计等. 只有将分配到容器的资源进行控制,才能避免多个容器同时运行时对宿主机系统的资源竞争.每个控制组是一组 ...
- Linux systemd资源控制初探
Linux systemd资源控制初探 本文记录一次cgroup子目录丢失问题,并简单探索了Linux systemd的资源控制机制. 问题现象 我们希望通过systemd拉起服务并通过cgroup限 ...
随机推荐
- Redis究竟为什么这么快?
Redis为什么这么快? 完全基于内存,数据存在内存中,绝大部分请求是纯粹的内存操作,非常快速,跟传统的磁盘文件数据存储相比,避免了通过磁盘IO读取到内存这部分的开销. 数据结构简单,对数据操作也简单 ...
- Memcached笔记——(一)安装&常规错误&监控
08年的时候接触过Memcached,当时还对它的客户端产品嗤之以鼻,毕竟手工代码没有各种ORM原生XML配置方便.尽管如此,Memcached现在已经成了服务器架构里不可或缺的一部分! 相关链接: ...
- 定时任务管理之qinglong
定时任务,是在日常开发需求中总会遇到的,我们往往会有一些简单的脚本工作,希望能够每小时或每天执行一次.当这类需求变得多起来后,这些零散的任务脚本就会变得难以管理,尤其是它们可能由不同的脚本语言编写而成 ...
- S2P销讯通·CRM-移动的客户关系精细化管理
S2P销讯通·CRM是一款专为医药企业设计的移动客户关系管理软件.该软件安装在手机上,集主数据管理.辖区指标管理.客户管理.SFE管理.OTC动销管理.精细化招商管理.市场活动管理以及流向采集清洗与统 ...
- RocksDB 内存超限问题剖析
作者:来自 vivo 互联网服务器团队- Zeng Luobin 在使用 RocksDB 存储引擎的过程中,有部分开发者遇到了内存使用超出预期的情况.本文针对这一问题展开了深入分析,从内存使用原理.R ...
- 为了改一行代码,我花了10多天时间,让性能提升了40多倍---Pascal架构GPU在vllm下的模型推理优化
ChatGPT生成的文章摘要 这篇博客记录了作者在家中使用Pascal显卡运行大型模型时遇到的挑战和解决方案.随着本地大型模型性能的提升,作者选择使用vllm库进行推理.然而,作者遇到了多个技术难题, ...
- NATS: 对依赖注入支持
NuGet: NATS.Net 使用方法: serviceCollection.AddNats(); 在容器中添加了 2 个单例服务: NATS.Client.Core.NatsConnection ...
- django推导流程
目录 一.纯手撸web框架 二.基于wsgiref模块 三.代码封装优化 四.动静态网页 五.jinja2模块 六.前端.后端.数据库三者联动 一.纯手撸web框架 1.web框架的本质 理解1:连接 ...
- 2024-12-21:从魔法师身上吸取的最大能量。用go语言,在一个神秘的地牢里,有 n 名魔法师排成一列。每位魔法师都有一个能量属性,有的提供正能量,而有的则会消耗你的能量。 你被施加了一种诅咒,吸
2024-12-21:从魔法师身上吸取的最大能量.用go语言,在一个神秘的地牢里,有 n 名魔法师排成一列.每位魔法师都有一个能量属性,有的提供正能量,而有的则会消耗你的能量. 你被施加了一种诅咒,吸 ...
- Qt编写地图综合应用2-迁徙图
一.前言 在很多web系统中,尤其是大屏系统中,经常可以看到类似于飞机迁徙图的效果,这个在echart中也是最常用的一个效果,迁徙图既可以是一个飞机也可以是其他形状,然后有一条动态的移动轨迹来表示流向 ...