Безопасно ли удалять функтор во время его вызова? - PullRequest
1 голос
/ 07 ноября 2011

Допустим, у меня есть следующий код:

typedef std::function<void ()> func_type;

void some_func()
{
  // Irrelevant stuff here. Might take some time...
}

DWORD WINAPI thread_proc(LPVOID lpParameter)
{
  func_type& func = *static_cast<func_type*>(lpParameter);

  func();

  return 0;
}

int main()
{
  HANDLE handle;

  {
    std::function<void ()> my_func(some_func);

    handle = ::CreateThread(NULL, 0, &thread_proc, &my_func, 0, NULL);

    // Here we consider my_func won't be destroyed before its operator() is called in the other thread.
    // I know nothing guarantees that, but let's just say it does for this sample.
  }

  ::WaitForSingleObject(handle, INFINITE);

  return EXIT_SUCCESS;
}

Кажется, моя текущая реализация работает, но это не доказывает, что я не сталкиваюсь с неопределенным поведением.

Здесь my_func может быть уничтожено до того, как вызов к его operator() вернется.Но так как я не обращаюсь к my_func где-либо в some_func(), действительно ли это проблема?

Примечание: я не могу использовать std::thread или boost::thread, к сожалению.Я бы хотел.

Ответы [ 2 ]

3 голосов
/ 07 ноября 2011

Если он будет уничтожен до того, как произойдет func(), то вы вызываете функцию-член для недопустимого объекта.Вам нужно сделать копию, которая будет жить как минимум до func() звонка.

2 голосов
/ 07 ноября 2011

Это, безусловно, UB.Ваш комментарий неверный, нет ничего, что могло бы гарантировать, что operator() вызывается до уничтожения локального.На самом деле, я считаю вполне вероятным, что он будет уничтожен до начала выполнения нового потока.Сделайте это вместо:

typedef std::function<void ()> func_type;

void some_func()
{
  // Irrelevant stuff here. Might take some time...
}

DWORD WINAPI thread_proc(LPVOID lpParameter)
{
  func_type* func = static_cast<func_type*>(lpParameter);

  (*func)();

  delete func;

  return 0;
}

int main()
{
  HANDLE handle;

  {
    func_type* my_func = new func_type(some_func);

    handle = ::CreateThread(NULL, 0, &thread_proc, my_func, 0, NULL);
  }

  ::WaitForSingleObject(handle, INFINITE);

  return EXIT_SUCCESS;
}
...