`
qiezi
  • 浏览: 499753 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

D语言的RAII支持

    博客分类:
  • D
阅读更多
RAII(Resource Acquisition Is Initialization 资源获得即初始化)是管理资源的一种方式,它在构造对象时初始化资源,析构对象时释放资源,有时也把这2个过程分为RAII和RRID(Resource Release Is Destruction 资源释放即析构),这通常需要语言支持。

大部分语言都支持RAII,RRID则有少数语言不支持,这些语言无法在域结束时自动销毁栈上分配的对象,java就是这种。

先来看看一个简单的JDBC调用过程:
Connection conn = null;
Statement stmt = null;
ResultSet rset = null;
try{
conn = createConnection();
stmt = conn.prepareStatement("SELECT * FROM USERS");
rset = stmt.executeQuery();
// 使用rset ...
}finally{
  if(rset!=null)rset.close();
  if(stmt!=null)stmt.close();
  if(conn!=null)conn.close();
}

C++中在栈上分配的对象离开它的作用域时会自动调用析构函数,类似功能的代码大概只要写成这样就可以了:
conn = createConnection();
stmt = conn.prepareStatement("SELECT * FROM USERS");
rset = stmt.executeQuery();
// 使用rset ...

如果析构函数中调用了close,它会在这几个变量离开作用域时按它们声明的相反顺序调用析构函数,也就达到了按这个顺序进行close的效果。

考虑到上面的Connection/Statement/ResultSet都是接口,如果在C++中也来这样操作接口的话,同样无法享受这种便利,因为在C++中用接口来操作意味着你必须使用指针,不幸的是指针没有析构函数,它只是简单类型。不过我们可以把这个工作委托给另一个对象,由这个对象来调用析构函数,你可以使用auto_ptr。或者可以参考ScopeGuard(由Andrei Alexandrescu & Petru Marginean 实现),它可以调用一个指定的方法,而不限于析构一个对象。C++能做到这些,因为C++栈上分配的对象在离开作用域时会自动析构,即便是发生异常也风雨无阻,别在析构函数中再抛异常就行了。

auto_ptr版本:
auto_ptr<Connection> conn (createConnection());
auto_ptr<Statement> stmt (conn->prepareStatement("SELECT * FROM USERS"))
auto_ptr<ResultSet> rset (stmt->executeQuery());
// 使用rset ...

ScopeGuard版本:
template <class T>
void ReleaseObject(T* obj){
    delete (T*)obj;
}
Connection* conn = createConnection();
ScopeGuard connGuard(ReleaseObject<Connection>, conn);
Statement* stmt = conn->prepareStatement("SELECT * FROM USERS");
ScopeGuard connGuard(ReleaseObject<Statement>, stmt);
ResultSet* rset = stmt->executeQuery();
ScopeGuard connGuard(ReleaseObject<ResultSet>, rset);
// 使用rset ...

ScopeGuard使用起来稍麻烦,原因是它不是为了析构对象而设计的,它是为了在自己析构时,执行一个指定任务,用起来很灵活。

C#使用using来达到相同的功能,不熟悉也不用它,就不去找代码了。

如果用ruby来做,我想可能是这样吧:
createConnection do |conn|
  conn.preparedStatement("SELECT * FROM USERS") do |stmt|
    rset = stmt.executeQuery();
    # 使用 rset ...
  end
end

由于代码都在块中,只需要在调用块的前后初始化及释放就可以了,从这点上来说,java也可以这样做,代码丑了点而已。。。

最后看看D语言是怎么做的吧:
scope Connection conn = createConnection();
scope Statement stmt = conn.prepareStatement("SELECT * FROM USERS");
scope ResultSet rset = stmt.executeQuery();
// 使用 rset ...

上面的Connection/Statement/ResultSet都可以是接口,作为“C++的改良者”,看起来至少在语法上它有所改进。可以看到它所用的代码不如C++/java这么多,也不需要C#和ruby这样构造出一“块”代码。

[注:上面用的scope关键字,原来是用auto,0.174中似乎说RAII中使用的auto应该被scope代替。]

D语言还从语言层次上提供了scope guard:
Connection conn = createConnection();
scope(exit) conn.close();
Statement stmt = conn.prepareStatement("SELECT * FROM USERS");
scope(exit) stmt.close();
ResultSet rset = stmt.executeQuery();
scope(exit) rset.close();
// 使用 rset
分享到:
评论
4 楼 qiezi 2006-11-23  
“擦屁股大法”。。。还挺形象的
3 楼 cookoo 2006-11-23  
让我想起ajoo以前那篇‘擦屁股大法’。。。
2 楼 qiezi 2006-11-21  
to ideage:

stmt和rset不需要using来管理吗?
using( Connection conn = createConnection() ){
  using (Statement stmt = conn.prepareStatement("SELECT * FROM USERS")){
    using (ResultSet rset = stmt.executeQuery()){
      // 使用 rset ...
    }
  }
}

不需要写成这样?我对C#不熟悉。
1 楼 ideage 2006-11-21  
c# code:

using( Connection conn = createConnection() )
{
  Statement stmt = conn.prepareStatement("SELECT * FROM USERS"); 
  ResultSet rset = stmt.executeQuery(); 
  // 使用 rset ...
}

相关推荐

    D语言教程

    - 还会介绍如何配置文本编辑器或IDE(集成开发环境)来支持D语言的开发。 3. **编写第一个程序**: - 本部分通过一个简单的“Hello, World!”程序示例,让读者亲自动手实践。 - 这有助于理解D语言的基本语法结构...

    D 语言 2.0 编程参考手册(上,中,下)

    5. **范围(Scope)**:D语言的范围解析运算符(`~=`)用于定义作用域,这可以自动清理资源,类似于C++的RAII(Resource Acquisition Is Initialization)。 6. **异常处理**:D语言支持异常处理,允许通过`try-...

    d语言:dmc8.50

    4. 内存管理:D语言内置垃圾回收机制,同时也允许手动内存管理,提供了丰富的内存安全特性,如智能指针和RAII(Resource Acquisition Is Initialization)。 5. 错误处理:D语言采用异常处理机制来捕获运行时错误,...

    D Programming Language

    D语言引入了**RAII**(Resource Acquisition Is Initialization)的概念,通过构造函数和析构函数自动管理资源的生命周期,降低了内存泄漏的风险。 ##### 3.5 性能优化 - **零成本抽象**:D语言实现了零成本抽象,...

    aed1

    它是一种静态类型的、编译式的、通用的、大小写敏感的、不仅支持过程化编程,也支持面向对象编程的语言。C++ 的主要特点包括: 1. **面向对象**:C++ 提供了类和对象的概念,使得代码可以被组织成可重用的模块。类...

    Konark:C++ 2D 游戏引擎

    科纳克(Konark)是一款基于C++语言开发的2D游戏引擎,专为游戏开发者提供高效、灵活且易用的工具,以创建丰富多彩的2D游戏世界。C++作为底层编程语言,使得Konark在性能上具有显著优势,同时其高度的可定制性和面向...

    AED2-P1-C_IDE

    1. **C++基础**:C++是一种静态类型的、编译式的、通用的、大小写敏感的、不仅支持过程化编程,也支持面向对象编程的程序设计语言。它继承了C语言的特性,并增加了类、模板、异常处理等面向对象的特性。 2. **数据...

    gcc_gcc_

    它是一个开源的、跨平台的编译器套件,支持C、C++、Objective-C、Fortran、Ada、Go、D等多种编程语言。GCC不仅包括前端编译器,还包含后端链接器和库,使得开发者能够在各种操作系统和硬件平台上构建和运行程序。 *...

    Bumble_D

    【标题】"Bumble_D" 是一个项目或软件的代号,可能是一个使用 C++ 编程语言开发的应用程序。由于信息有限,我们主要从 C++ 的核心概念和编程实践来探讨相关知识点。 C++ 是一种强类型、静态类型的编程语言,它在 C ...

    Beginning C++17, 5th Edition

    7. **内存管理**:理解动态内存分配、智能指针(如std::unique_ptr、std::shared_ptr)以及RAII(Resource Acquisition Is Initialization)原则,以避免内存泄漏。 8. **并发编程**:简述C++11及后续版本提供的...

    bndr-engine:Windows x64机器上的C ++游戏的游戏引擎

    “bndr-engine”是一个专为Windows x64平台设计的游戏引擎,主要用C++语言编写,专注于2D游戏开发。游戏引擎是游戏开发的核心,它提供了图形渲染、物理模拟、音频处理、输入管理等多种功能,帮助开发者快速构建游戏...

    Morpheus:用现代C ++编写的实验性Game Boy Advance和Nintendo DS游戏引擎

    现代C++支持模板元编程、智能指针、RAII(Resource Acquisition Is Initialization)等高级特性,这些都使得Morpheus在内存管理、性能优化和代码安全性方面具有优势。 二、Game Boy Advance与Nintendo DS硬件特性...

    Defer:C的Defer陈述式

    在C语言中,`defer`语句是一...在C++中,可以使用RAII(Resource Acquisition Is Initialization)原则和智能指针来更好地管理资源,而在Go等其他语言中,`defer`是语言内置的一部分,提供了更强大的保障和简洁的语法。

    Bjarne Stroustrup的FAQ:C++的风格与技巧

    - **答案**:C++没有提供类似Java中的finally块,但可以通过RAII(资源获取即初始化)模式来实现相似的功能。通过确保资源在对象生命周期结束时释放,可以达到与finally相同的效果。 #### 2.8 为何没有提供auto_...

    Bjarne Stroustrup的FAQ

    - 在适当的地方使用RAII(Resource Acquisition Is Initialization)原则。 - **异常处理的注意事项:** - 在C++中,使用异常处理可以更好地管理程序中的错误。 - 需要注意的是,抛出异常后的程序状态可能会变得...

    OpenHadouken

    OpenHadouken是用C++语言编写的,C++是一种强类型、静态类型的通用编程语言,以其高效性、灵活性和强大的系统级编程能力而闻名。它不仅支持面向过程编程,还引入了面向对象的概念,使得代码更加模块化和易于维护。...

    你好

    7. **C++11及以后的标准**:自C++11以来,C++引入了许多新特性,如lambda表达式、右值引用、auto关键字、类型推断、强类型枚举、并发支持等,进一步提升了语言的现代性和效率。 8. **内存管理**:C++允许直接操作...

    计算机基础精华

    - **D&B&FWAlgorithm** - Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法分别用于解决单源最短路径问题、带负权边的单源最短路径问题和任意两点间的最短路径问题。 - **应用** - 图的应用非常广泛,包括...

Global site tag (gtag.js) - Google Analytics