长跳破坏 RAII 的简单例子_Ruby_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > Ruby > 长跳破坏 RAII 的简单例子

长跳破坏 RAII 的简单例子

 2011/8/10 17:30:12  night_stalker  http://night-stalker.iteye.com  我要评论(0)
  • 摘要:ResourceAcquisitionIsInitialization是C++卖点之一,简单来说就是退出局部作用域的时候局部变量的析构函数就会被自动调用.在RAII特性上可以做自动指针,可以实现类似GC的功能,STL和Boost都有智能指针和自动指针的实现.但是如果作用域里调用的函数用了长跳转跳出去了,析构函数就不会被调用,内存泄漏就由此而起,而且...长跳转其实在Ruby里到处都是...例如:deffind_first_alistlist.each{|i|return'a'ifi==a
  • 标签:例子
Resource Acquisition Is Initialization 是 C++ 卖点之一, 简单来说就是退出局部作用域的时候局部变量的析构函数就会被自动调用. 在 RAII 特性上可以做自动指针, 可以实现类似 GC 的功能, STL 和 Boost 都有智能指针和自动指针的实现.

但是如果作用域里调用的函数用了长跳转跳出去了, 析构函数就不会被调用, 内存泄漏就由此而起, 而且 ... 长跳转其实在 Ruby 里到处都是 ... 例如:

def find_first_a list
  list.each {|i| return 'a' if i == a } # return in proc => long jump!
  return false
end


下面用一个简单的 extension 验证看似正确的代码是怎么内存泄漏的 ...

ra.cpp
#include "iostream"
#include "ruby.h"

namespace {
  // 典型的 C++ 类: 在构造函数分配资源, 在析构函数销毁资源
  struct C {
    int *a;
    C() {
      a = new int[100];
      std::cout << "constructor called\n";
    }
    ~C() {
      delete[] a;
      std::cout << "destructor called\n";
    }
  };

  VALUE f(VALUE self) {
    // 构造函数被调用
    C c;
    // block 参数
    VALUE args[0];
    // 如果 block 中用了 return 产生了长跳转, 下面的代码都不会被调用
    rb_yield((VALUE)args);
    return Qnil;
    // RAII 隐藏了在这里调用 c 的析构函数的代码
  }
}

extern "C"
void Init_ra() {
  VALUE c = rb_define_class("C", rb_cObject); // 定义 Ruby 类 C
  rb_define_method(c, "f", RUBY_METHOD_FUNC(f), 0); // 定义 Ruby 方法 C#f
}


编译生成扩展库 (ra.so 或 ra.bundle)
ruby -rmkmf -e "create_makefile 'ra'"
make


测试长跳 (同一目录下的 test.rb)
require_relative "ra"

def raii_broken
  C.new.f {
    return # long jump !
  }
end

def raii_normal
  C.new.f {}
end

puts "RAII broken:"
raii_broken
puts "\nRAII normal:"
raii_normal


结果: 不用 return 就没泄漏, 用 return 就泄漏了
→ ruby -v
ruby 1.9.3dev (2011-07-10 trunk 32499) [x86_64-darwin10.8.0]
→ ruby test.rb 
RAII broken:
constructor called

RAII normal:
constructor called
destructor called


补充:
GCC 的 cleanup attribute 扩展也是 RAII, 还没时间试验, 估计也是 ...
发表评论
用户名: 匿名