Шаблон C ++: проверьте, можно ли "игнорировать" деструктор типа - PullRequest
1 голос
/ 08 ноября 2019

Во-первых, позвольте мне сделать этот вопрос более конкретным.

Сказав

проверить, можно ли "игнорировать" деструктор типа

Я имею в виду

проверить, нет ли у класса побочных эффектов, когда его экземпляры умирают.

Что я делаю:

Я пишу библиотеку для сборки мусора для наших проектов 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_destructible и is_trivially_destructible, но эти два не могут удовлетворить мое требование. Особенно пример 4.

Более того: Приветствуются любые особенности компилятора, которые могут решить эту проблему.

1 Ответ

5 голосов
/ 08 ноября 2019

Черта типа std::is_trivially_destructible - это то, что вам нужно. Смотрите здесь . Единственный случай, когда выходной сигнал отличается от желаемого, - S2. К сожалению, в C ++ отсутствуют конструкции для просмотра пустого пользовательского деструктора как тривиального.

Редактировать:

Нет способа исключить условие при virtual nessиз вышеупомянутой черты, так что единственный оставшийся вариант - создать свою собственную черту. Это требует дополнительной работы на стороне пользователя, ничего из коробки. Существует несколько способов различения пользовательских типов с помощью пользовательского предиката:

  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. при наличии присутствия члена (например, псевдоним типа - тег - как определяются прозрачные компараторы )

  3. по шаблонным специализациям (неисключая 1. и 2.):

    template <typename T>
    struct can_be_forgotten : std::is_trivially_destructible<T> {};
    
    template <>
    can_be_forgotten<S8> : std::true_type {};
    
  4. может быть больше ...

Более важно , вопрос, который должен был бытьСперва спросим, ​​не является ли это тем, что компилятор делает для вас автоматически (создавая один и тот же код с вызовами деструкторов или без них). Это лучше проверить самим.

PS Я надеюсь, что мы все время думали о новом размещении, потому что в противном случае произошли бы утечки памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...