gpt4 book ai didi

c++ - 如果用户使用 Rice 在 Ruby 中重新定义 initialize(),则避免 C++ 代码中的段错误

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:28:19 26 4
gpt4 key购买 nike

在为 Ruby 编写 C++ 扩展时,我一直在努力解决的一个问题是,即使用户做了愚蠢的事情,也要让它真正安全。那时他应该得到异常,但绝不是 SegFault。一个具体的问题如下:我的 C++ 类有一个非平凡的构造函数。然后我使用 Rice API 来包装我的 C++ 类。如果用户在他的 Ruby 代码中重新定义了 initialize() ,那么 Rice 创建的 initialize() 函数就会被覆盖,对象既不会被分配也不会被初始化。一个玩具示例如下:

class Person {
public:
Person(const string& name): m_name (name) {}
const string& name() const { return m_name; }
private:
string m_name;
}

然后我像这样创建 Ruby 类:

define_class<Person>("Person")
.define_constructor(Constructor<Person, const string&>(), Arg("name"))
.define_method("name", &Person::name);

然后下面的 Ruby 代码会导致段错误

require 'MyExtension'
class Person
def initialize
end
end
p = Person.new
puts p.name

有两种可能性我会很高兴:禁止以某种方式覆盖 Ruby 中的初始化函数或检查 C++,如果对象已正确分配,否则抛出异常。

我曾经直接使用过 Ruby C API,然后很容易。我刚刚分配了一个虚拟对象,它由一个空指针和一个在 allocate() 函数中设置为 false 的标志组成,在 initialize 方法中,我分配了真实对象并将标志设置为 true。在每种方法中,我检查该标志并引发异常,如果它是假的。然而,我用 Ruby C API 写了很多愚蠢的重复代码,我首先必须包装我的 C++ 类,以便它们可以从 C 访问,然后包装和解包 Ruby 类型等,另外我必须检查这个愚蠢的标志每一种方法,所以我迁移到 Rice,这真的很好,我对此感到非常高兴。

然而,在 Rice 中,程序员只能提供一个构造函数,该构造函数在 rice 创建的 initialize() 函数中调用,而 allocate() 函数是预定义的,什么也不做。我认为没有一种简单的方法可以更改此设置或以“官方”方式提供自己的分配功能。当然,我仍然可以使用 C API 来定义分配函数,所以我尝试以某种方式混合使用 C API 和 Rice,但后来我变得非常讨厌,我遇到了奇怪的 SegFaults 而且它真的很难看,所以我放弃了那个想法.

这里有人有使用 Rice 的经验吗?有人知道如何确保它安全吗?

最佳答案

这个怎么样

class Person
def initialize
puts "old"
end
alias_method :original_initialize, :initialize

def self.method_added(n)
if n == :initialize && !@adding_initialize_method
method_name = "new_initialize_#{Time.now.to_i}"
alias_method method_name, :initialize
begin
@adding_initialize_method = true
define_method :initialize do |*args|
original_initialize(*args)
send method_name, *args
end
ensure
@adding_initialize_method = false
end
end
end
end

class Person
def initialize
puts "new"
end
end

然后调用Person.new输出

old
new

即我们的旧初始化方法仍然被调用

这使用了 method_added Hook ,每当添加(或重新定义)方法时都会调用该 Hook ,此时新方法已经存在,因此阻止他们这样做为时已晚。相反,我们为新定义的 initialize 方法取了别名(您可能需要更努力地工作以确保方法名称是唯一的)并定义另一个初始化方法,它首先调用旧的初始化方法,然后调用新的初始化方法。

如果此人是明智的并从他们的初始化调用 super 那么这将导致您的原始初始化方法被调用两次 - 您可能需要防范这种情况

您可以从 method_added 中抛出一个异常来警告用户他们正在做坏事,但这并不能阻止方法被添加:该类现在处于不稳定状态.您当然可以在他们的方法之上实现您的原始初始化方法。

关于c++ - 如果用户使用 Rice 在 Ruby 中重新定义 initialize(),则避免 C++ 代码中的段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12496817/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com