C ++模板:检查类型的析构函数是否可以被“忽略”

rea*_*esk 1 c++ templates

首先,让我使这个问题更具体。

通过说

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

我意思是

检查类在实例消失时是否没有副作用。

我在做什么:

我正在为我们的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
Run Code Online (Sandbox Code Playgroud)

我尝试将is_destructible和结合在一起is_trivially_destructible,但是这两个不能满足我的要求。特别是示例4。

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

Log*_*uff 5

std::is_trivially_destructible类型特质是你所需要的。看这里。输出与期望值不同的唯一情况是S2。不幸的是,C ++缺乏将空的用户定义的析构函数视为琐碎的构造。

编辑:

无法virtual从上述特征中排除关于满足度的条件,因此剩下的唯一选择就是创建自己的特征。这就需要在用户端做额外的工作,没有现成的东西。使用自定义谓词区分用户定义类型有几种方法:

  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>;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 通过成员存在(例如,类型别名-标签-如何定义透明比较器

  3. 通过模板专长(不限于1.和2.):

    template <typename T>
    struct can_be_forgotten : std::is_trivially_destructible<T> {};
    
    template <>
    can_be_forgotten<S8> : std::true_type {};
    
    Run Code Online (Sandbox Code Playgroud)
  4. 也许更多...

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

PS我希望我们一直都在考虑新的布局,否则会导致内存泄漏。