【问题标题】:Strange behaviour with costructors in Ruby C extensionRuby C 扩展中的构造函数的奇怪行为
【发布时间】:2011-12-08 13:02:49
【问题描述】:

我在 Ruby C 扩展中看到了类构造函数的奇怪行为。
看一个例子:我们有一个类Foo,它是一个C扩展和一个类Bar,它继承自Foo

extconf.rb

# extconf.rb
require 'mkmf'
create_makefile('foo/foo')

foo.c

// foo.c
#include "ruby.h"
#include <stdio.h>

VALUE
foo_new (VALUE class)
{
  printf ("foo_new\n");
  int *ptr;
  VALUE tdata = Data_Wrap_Struct (class, 0, 0, ptr);
  rb_obj_call_init (tdata, 0, 0);
  return tdata;
}

VALUE
foo_init (VALUE self)
{
  printf ("foo_init\n");
  return self;
}

VALUE
foo_plus_one (VALUE self, VALUE x)
{
  printf ("foo_plus_one\n");
  return INT2FIX (FIX2INT (x) + 1);
}

void
Init_foo ()
{
  VALUE foo = rb_define_class ("Foo", rb_cObject);
  rb_define_singleton_method (foo, "new", foo_new, 0);
  rb_define_method (foo, "initialize", foo_init, 0);
  rb_define_method (foo, "plus_one", foo_plus_one, 1);
}

bar.rb

# bar.rb
require './foo'

class Bar < Foo
end

好吧,让我们看看奇怪的东西...
在这种情况下一切正常:

x = Bar.new

我们得到 2 个打印件:foo_newfoo_init
好的,但是如果我们以这种方式更改类 Bar

# bar.rb
require './foo'

class Bar < Foo
  def initialize(param = 1)
  end
end

如果我们运行,我们会得到第一个奇怪的东西

x = Bar.new

我们只得到 1 个打印:foo_new。还有foo_init ??
好的,我们可以通过显式调用Foo的构造函数来绕过这个问题:

# bar.rb
require './foo'

class Bar < Foo
  def initialize(param = 1)
    super()
  end
end

如果我们调用 x = Bar.new,我们会得到 2 个打印:foo_newfoo_init

第二个奇怪的东西是这样的: 如果我们打电话

x = Bar.new(2)

我们得到错误

in `new': wrong number of arguments(1 for 0) (ArgumentError)

但是Bar的构造函数接受一个带默认值的参数。
为什么这个?这是 Ruby 错误吗?

(使用 ruby​​1.9.3-p0 [ x86_64 ] 测试)

【问题讨论】:

  • p Bar.new.class 打印出Foo,对吧?
  • Bar.new.class 打印Bar, Foo.new.class 打印Foo

标签: c ruby constructor ruby-c-extension


【解决方案1】:

您将::new 定义为不接受任何参数,因此应为wrong number of arguments(1 for 0)。无论如何,::new 不应该被重新定义。正确的做法是定义::allocate 方法(::new 在内部调用它)。

这应该可行:

// foo.c
#include "ruby.h"
#include <stdio.h>

void foo_free (void *ptr) {
    free (ptr);
}

VALUE foo_alloc (VALUE class) {
    printf ("foo_alloc\n");
    int *ptr = malloc(sizeof(int));
    return Data_Wrap_Struct (class, 0, foo_free, ptr);
}

VALUE foo_init (VALUE self) {
    printf ("foo_init\n");
    return self;
}

void Init_foo (void) {
    VALUE cFoo = rb_define_class ("Foo", rb_cObject);
    rb_define_alloc_func (cFoo, foo_alloc);
    rb_define_method (cFoo, "initialize", foo_init, 0);
}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-02
相关资源
最近更新 更多