【问题标题】:Wrapping entities from Z3 C API从 Z3 C API 包装实体
【发布时间】:2013-03-14 14:58:33
【问题描述】:

我正在 Z3 中试验枚举排序,如 How to use enumerated constants after calling of some tactic in Z3? 中所述,我注意到我可能对如何正确使用 C 和 C++ api 有一些误解。让我们考虑以下示例。

   context z3_cont;
   Z3_symbol e_names[2 ];
   Z3_func_decl e_consts[2];
   Z3_func_decl e_testers[2];

   e_names[0] = Z3_mk_string_symbol(z3_cont, "x1"); 
   e_names[1] = Z3_mk_string_symbol(z3_cont, "x2"); 
   Z3_symbol e_name = Z3_mk_string_symbol(z3_cont, "enum_type");  
   Z3_sort new_enum_sort = Z3_mk_enumeration_sort(z3_cont, e_name, 2, e_names, e_consts, e_testers);

   sort enum_sort = to_sort(z3_cont, new_enum_sort);
   expr e_const0(z3_cont), e_const1(z3_cont);

/* WORKS!
   func_decl a_decl = to_func_decl(z3_cont, e_consts[0]);
   func_decl b_decl = to_func_decl(z3_cont, e_consts[1]);
   e_const0 = a_decl(0, 0);
   e_const1 = b_decl(0, 0);   
*/
   // SEGFAULT when doing cout
   e_const0 = to_func_decl(z3_cont, e_consts[0])(0, 0);
   e_const1 = to_func_decl(z3_cont, e_consts[1])(0, 0);

   cout << e_const0 << " " << e_const1 << endl;

我希望这两种代码变体能够用智能指针很好地包装 C 实体 Z3_func_decl,以便我可以与 C++ api 一起使用,但只有第一个变体似乎是正确的。所以我的问题是

  1. 第二种方法不起作用是正确的行为吗?如果是这样,我怎样才能更好地理解为什么不应该这样做的原因?

  2. 未包装的 C 实体会发生什么,例如 Z3_symbol e_name - 这里我不包装它,我不增加引用。那么内存会被妥善管理吗?使用它安全吗?什么时候对象会被销毁?

  3. 一个小问题:我没有看到 C++ api 中的 to_symbol() 函数。这只是不必要的吗?

谢谢。

【问题讨论】:

    标签: z3


    【解决方案1】:
    1. 每当我们创建一个新的 Z3 AST 时,如果 n 的引用计数器为 0,Z3 可能会垃圾收集一个 AST n。在有效的代码段中,我们在我们之前包装了 e_consts[0]e_consts[1]创建任何新的 AST。当我们包装它们时,智能指针将碰撞它们的引用计数器。 这就是它起作用的原因。在崩溃的那段代码中,我们包装e_consts[0],然后在包装e_consts[1]之前创建e_const0。因此,e_consts[1] 引用的 AST 在我们有机会创建 e_const1 之前被删除。

      顺便说一句,在下一个正式版本中,我们将支持在 C++ API 中创建枚举类型:http://z3.codeplex.com/SourceControl/changeset/b2810592e6bb

      此更改已在夜间构建中可用。

    2. Z3_symbol 不是引用计数对象。它们是持久的,Z3 维护一个包含所有已创建符号的全局表。我们应该将符号视为唯一的字符串。

    3. 请注意,我们可以使用类symbol 和构造函数symbol::symbol(context &amp; c, Z3_symbol s)。函数to_* 用于包装使用带有智能指针的C API 创建的对象。我们通常有一个函数to_A,如果有一个C API 函数返回一个A 对象,并且C++ 中没有等效的函数/方法。

    【讨论】:

    • 感谢您的清晰解释。我根据我上次的编辑更新了您回复中的常量名称,以便于代码理解。
    • 假设 Z3 不会垃圾收集仍然未引用计数的对象,而我将逐渐包装它们是否足够安全(假设我在那里有 100 个枚举常量)。正如你所说——只要引用计数器为零,Z3 就会对它们进行垃圾收集。 Z3 是正确的多线程库,所以我只是想如果 GC 碰巧在一个单独的线程中工作并且会在我有机会包装它们之前收集 Z3_AST,即使我打算并且不制作任何新的 AST :)
    • 是的,我们可以假设 Z3 在我们逐渐包装对象时不会进行垃圾收集。如果我们调用分配另一个 AST 的 API,Z3 只会垃圾收集一个 AST。关于多线程,Z3没有单独的垃圾回收线程。
    猜你喜欢
    • 1970-01-01
    • 2012-12-19
    • 2011-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多