Благодаря советам @ Macke у меня есть улучшенное решение, подобное следующему:
~MyClass(){
DEFINE_THREAD_LOCAL(std::queue< std::shared<void> >, q)
bool reentrant = !q.empty();
q.emplace(std::move(p)); //IMPORTANT!
if(reentrant) return;
while(!q.empty()){
auto pv = q.front();
q.pop();
}
}
DEFINE_THREAD_LOCAL
- это макрос, который определяет переменную (параметр 2) в качестве указанного типа (параметр 1) с потокомтип локального хранилища, что означает, что для каждого запущенного потока не более одного экземпляра.Поскольку ключевое слово thread_local
по-прежнему недоступно для основных компиляторов, я должен предположить, что такой макрос будет работать для компиляторов.
Для однопоточных программ DEFINE_THREAD_LOCAL(type, var)
это просто
static type var;
Преимущество этого решения в том, что оно не требует изменения определения класса.
В отличие от решения @ Macke, я использую std::queue
вместо std::stack
, чтобы сохранить порядок уничтожения.
В данном тестовом примере q.size()
никогда не будет больше 1. Однако это только потому, что этот алгоритм является первым в ширину.Если MyClass
имеет больше ссылок на другой экземпляр MyClass
, q.size()
достигнет больших значений.
ПРИМЕЧАНИЕ. Важно помнить, что std :: move используется для передачи p в очередь.Вы не решили проблему, если забыли это сделать, вы просто создаете и уничтожаете новую копию p, и после видимого кода уничтожение все равно будет рекурсивным.
ОБНОВЛЕНИЕ: исходный опубликованный код имеетпроблема: q
будет изменено в pop()
вызове.Решением является кэширование значения q.front()
для последующего уничтожения.