【问题标题】:C++ template: check if a type's destructor can be "ignored"C++ 模板:检查类型的析构函数是否可以“忽略”
【发布时间】:2019-11-08 08:53:09
【问题描述】:

首先,让我把这个问题说得更具体一些。

说出来

检查一个类型的析构函数是否可以“忽略”

我是认真的

检查一个类在实例死亡时是否没有副作用。

我在做什么:

我正在为我们的 C++ 项目编写一个垃圾回收库,我需要提高性能。如果我能检测到传入的类型T在销毁时没有副作用,我可以只检查所有活着的对象,剩下的都是垃圾,可以标记为“垃圾”(典型的年轻代收集技术) )。但如果它有副作用,我必须扫描每一个垂死的对象并运行它的析构函数。

例如:

struct S1 {
  int i;
}; // can be ignored

struct S2 {
  int i;
  ~S2() {

  }
}; // can be ignored

struct S3 {
  S3() {
    std::cout << "S3()" << std::endl;
  }
  virtual ~S3() {
    std::cout << "~S3()" << std::endl;
  }
}; // can not be ignored, destructor has side effect

struct S4 {
  S3 s3;
}; // can not be ignored, destructor has side effect(calling s3's destructor) 
// this is the most tricky one I tried and failed.

struct S5 {
  S3 s3;
  ~S5() {

  }
}; // same with S4

struct S6 : public S3 {

};// can not be ignored, super destructor has side effect

struct S7 : public S1 {

};// can be ignored, super destructor does not have side effect

struct S8 {
  virtual ~S8() = default;
}; // can be ignored
// which cannot use is_trivially_destructible

struct S9 : public S8 {

}; // can be ignored

我尝试将is_destructibleis_trivially_destructible 组合在一起,但这两个不能满足我的要求。尤其是例子4。

更重要的是: 欢迎任何可以解决此问题的编译器特定功能。

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    std::is_trivially_destructible 类型特征是您所需要的。看here。输出与预期不同的唯一情况是S2。不幸的是,C++ 缺乏将空的用户定义的析构函数视为微不足道的构造。

    编辑:

    没有办法从上面的特征中排除virtualness 的条件,所以剩下的唯一选择就是创建你自己的特征。这需要在用户端做额外的工作,没有开箱即用的东西。有几种方法可以用自定义谓词区分用户定义的类型:

    1. 通过某种类型的继承:

      class my_class : private can_be_forgotten_tag { ... };
      
      template <typename T>
      using can_be_forgotten_v =
          std::is_trivially_destructible<T> ||
          std::is_base_of<can_be_forgotten_tag, T>;
      
    2. presence of a member(例如类型别名-标签-transparent comparators是如何定义的)

    3. 按模板特化(不限于 1. 和 2.):

      template <typename T>
      struct can_be_forgotten : std::is_trivially_destructible<T> {};
      
      template <>
      can_be_forgotten<S8> : std::true_type {};
      
    4. 也许更多...

    更重要的是,首先应该问的问题是这是否已经不是任何编译器自动为您做的事情(无论是否使用析构函数调用都生成相同的代码)。那最好自己检查一下。

    附:我希望我们一直在考虑placement-new,否则会出现内存泄漏。

    【讨论】:

    • 对不起,我又添加了两个 case,这是默认的 deturctor case,如果您能再次提供帮助,我们将不胜感激。
    • @sp2danny,这不是真的。除非析构函数有副作用,否则您可以重用内存而不调用它。 stackoverflow.com/questions/20541987/…
    • @reavenisadesk 已编辑,但您不会满意。很抱歉耽搁了。
    • 我决定不要偏执于琐碎的析构函数无法处理的情况。谢谢你的回答。
    猜你喜欢
    • 1970-01-01
    • 2021-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    相关资源
    最近更新 更多