Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 08.01.2014, 13:06   #1
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию Почему деструктор вызывается два раза?

Здравствуйте.
Столкнулся со странной проблемой, локализовал ее и не могу понять почему так происходит:
Код:
#include <iostream>
#include <thread>
using namespace std;


class guarded_thread : public std::thread
{
public:
    using std::thread::thread;
    ~guarded_thread(void)       
    {
        std::cout << "here\n"; 
        if(this->joinable()) 
        this->join(); 
    }
    guarded_thread &operator=(guarded_thread &&) = default;
};

void tr_fn() { this_thread::sleep_for(chrono::seconds(2)); }

guarded_thread th;


int main() 
{
    th = guarded_thread {tr_fn};
    return 0;
}
// cout:
//       here
//       here
Как видно деструктор вызывается дважды. Сначала подумал баг (у меня gcc 4.8.1), попробовал запустить это код на онлайн компиляторе (clang 3.4) - результат тот же. Если запустить поток в месте объявления th а не в main, то деструктор вызывается один раз. Почему так происходит?
220Volt вне форума Ответить с цитированием
Старый 08.01.2014, 13:23   #2
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Если добавить еще глобальную структуру, то получим:
Код:
#include <iostream>
#include <thread>
using namespace std;


class guarded_thread : public std::thread
{
public:
    using std::thread::thread;
    ~guarded_thread(void)       
    {
        std::cout << "here\n"; 
        if(this->joinable()) 
        this->join(); 
    }
    guarded_thread &operator=(guarded_thread &&) = default;
};

void tr_fn() { this_thread::sleep_for(chrono::seconds(2)); }

guarded_thread th;

struct GG
{
    ~GG() {cout << "GG::destructor\n";}
}gg;

int main() 
{
    th = guarded_thread {tr_fn};
    return 0;
}
// cout:
//       here
//       GG::destructor
//       here
220Volt вне форума Ответить с цитированием
Старый 08.01.2014, 14:50   #3
Rififi
Старожил
 
Регистрация: 19.08.2009
Сообщений: 2,119
По умолчанию

220Volt

Как видно деструктор вызывается дважды. Сначала подумал баг (у меня gcc 4.8.1), попробовал запустить это код на онлайн компиляторе (clang 3.4) - результат тот же.

как ты думаешь, сколько в этой программе создается объектов guarded_thread?
Rififi вне форума Ответить с цитированием
Старый 08.01.2014, 14:54   #4
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Цитата:
Сообщение от Rififi Посмотреть сообщение
220Volt
...
как ты думаешь, сколько в этой программе создается объектов guarded_thread?
Думаю один. Пожалуйста, давайте без загадок, укажите конкретно что по-вашему не так.
220Volt вне форума Ответить с цитированием
Старый 08.01.2014, 15:05   #5
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Понял, я туплю, вопрос закрыт.

Последний раз редактировалось 220Volt; 08.01.2014 в 15:08.
220Volt вне форума Ответить с цитированием
Старый 08.01.2014, 15:41   #6
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Я не за то зацепился, но вопросы остались:
Код:
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <iostream>
#include <thread>
using namespace std;


class guarded_thread : public std::thread
{
public:
    using std::thread::thread;
    ~guarded_thread(void)       
    {
        if(this->joinable()) 
        this->join(); 
    }
    guarded_thread &operator=(guarded_thread &&) = default;
};

void tr_fn() 
{ 
    this_thread::sleep_for(chrono::seconds(1)); 
    Fl_Window *p = new Fl_Window {0, 0, Fl::w() / 2, Fl::h() / 2};
    p->show();
    Fl::run();
}

guarded_thread th;

int main() 
{
    th = guarded_thread {tr_fn};
    this_thread::sleep_for(chrono::seconds(2));  // #1
    return 0;
}
Если #1 закомментировать то окно не появится (не понимаю почему). Т.е. если поток в main отработает до того как порожденный поток успеет отобразить окно, то оно не появляется. Наверное мало у кого установлена FLTK, но может кто сталкивался.
220Volt вне форума Ответить с цитированием
Старый 08.01.2014, 18:06   #7
Son Of Pain
Участник клуба
 
Регистрация: 23.12.2010
Сообщений: 1,129
По умолчанию

А если переменную с потоком объявить локальной внутри main, поведение меняется?
Son Of Pain вне форума Ответить с цитированием
Старый 08.01.2014, 18:29   #8
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Цитата:
Сообщение от Son Of Pain Посмотреть сообщение
А если переменную с потоком объявить локальной внутри main, поведение меняется?
Так работает:
Код:
int main() 
{
    guarded_thread th {tr_fn};
    if(th.joinable()) th.join();

    return 0;
}
}
Задал вопрос на FLTK форуме https://groups.google.com/forum/#!to...al/uVsf73_b-mI

Не понятна мне логика - как завершение потока в main() влияет на остальные части программы? Ведь пока все потоки не завершатся ничего не должно быть разрушено.
220Volt вне форума Ответить с цитированием
Старый 08.01.2014, 21:19   #9
Son Of Pain
Участник клуба
 
Регистрация: 23.12.2010
Сообщений: 1,129
По умолчанию

Нет. После выхода из main уничтожаются все глобальные/статические объекты, и программа завершает работу, независимо от того, что происходит в остальных потоках.

Подозреваю, что в твоем случае в главном потоке успевает уничтожиться какой-то важный для fltk глобальный или статический объект до вызова деструктора второго потока. А второй поток тем временем пытается создать окно, не может этого сделать и спокойно джойнится.
Son Of Pain вне форума Ответить с цитированием
Старый 08.01.2014, 21:59   #10
220Volt
Форумчанин
 
Регистрация: 14.12.2012
Сообщений: 668
По умолчанию

Цитата:
Сообщение от Son Of Pain Посмотреть сообщение
Нет. После выхода из main уничтожаются все глобальные/статические объекты, и программа завершает работу, независимо от того, что происходит в остальных потоках.
....
Не буду утверждать, но сомневаюсь:
Код:
//#include <cstdlib>
#include <thread>
#include <iostream>

using namespace std;


struct Before {
    ~Before() { cout << "Before::destr\n"; }
}before;

void thr_fn()
{
    this_thread::sleep_for( chrono::seconds(3) );  // Ждем 3 секунды - можно успеть разрушить все глоб. объекты
    for(int i = 3;  i > 0;  -- i) {  
        cout << "tick\n";
        this_thread::sleep_for( chrono::seconds(1) );
    }
}

struct After {
    ~After() { cout << "After::destr\n"; }
}after;

guarded_thread thr;

int main() 
{
    thr = guarded_thread {thr_fn};
    return 0;
}
// tick
// tick
// tick
// After::destr
// Before::destr
Работает как положено. Да и очень не логично уничтожать объекты пока есть при_join_еные потоки.
220Volt вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Почему при перегруженных = и +, вызывается... WebbMan Общие вопросы C/C++ 18 13.12.2012 01:15
Почему вызывается деструктор? MrGukk Общие вопросы C/C++ 13 23.08.2012 17:42
Не вызывается деструктор kineziz Общие вопросы C/C++ 4 18.08.2012 15:54
два раза к одной таблице Kolik317 SQL, базы данных 2 26.12.2009 13:58
слово пишется два раза INDY-SAVER Microsoft Office Word 2 18.11.2009 23:49