2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 в чем все-таки ошибка?
Сообщение29.08.2012, 22:21 
Аватара пользователя


20/03/12
23
Здравствуйте!
Дали такую задачку: дана несложная программа на С++, которая демонстрирует асинхронный вызов функции. Необходимо в ней найти ошибку.
Код:
#include <windows.h>
#include <iostream>
#include <sstream>
#include <process.h>

namespace TST
{
    class Exception
    {
    public:
        Exception(const wchar_t* szwText)
            :   m_wstrText(szwText)
        {;};

        std::wstring What() const throw()
        {
            return m_wstrText;
        };

    protected:
        const std::wstring m_wstrText;
    };

    void le_chk(BOOL bResult, const char* file, int line)
    {
        if(!bResult)
        {
         std::clog << "An error " << GetLastError() << "occured";
            std::wostringstream os;
            os  << L"Win32 error occured: GetLastError returned " << GetLastError()
                << " in " << file << L"@" << line;
            throw Exception(os.str().c_str());
        };
    };

    #define TST_LE_CHECK(res)   le_chk((res), __FILE__, __LINE__)

    class CallBase
    {
    public:
        virtual void Call() = 0;
    };

    class AsyncActionBase
    {
    public:
        AsyncActionBase(CallBase* pCall)
            :   m_hThread(NULL)
        {
            unsigned uId = 0;
            m_hThread = (HANDLE)_beginthreadex(
                            NULL, 0, &AsyncActionBase::thread_proc,
                            (void*)pCall, 0, &uId);
            TST_LE_CHECK(!!m_hThread); // зачем двойное отрицание?
        };

        virtual ~AsyncActionBase()
        {
            if(m_hThread)
            {
                TST_LE_CHECK(WaitForSingleObject(m_hThread, INFINITE)
                    != WAIT_FAILED);
                TST_LE_CHECK(CloseHandle(m_hThread));
                m_hThread = NULL;
            };
        };
    protected:
        static unsigned __stdcall thread_proc(void * p)
        {
            try
            {
                ((CallBase*)p)->Call();
            }
            catch (const TST::Exception& excpt)
            {
                std::wcerr << excpt.What();
            };
            return 0;
        };
        HANDLE m_hThread;
    };

    class MyAsyncAction1
        :   public CallBase
        ,   public AsyncActionBase
    {
    public:
        MyAsyncAction1()
            :   AsyncActionBase(this) // передавать this в списке инициализации конструктору базового класса небезопасно,
        {                        // т.к. конструктор базового класса может воспользоваться еще неинициализированными
                                 //  членами производного класса
        };
       
        virtual ~MyAsyncAction1()
        {
        };

    //CallBase
        virtual void Call()
        {
            for(size_t i = 0; i < 100; ++i)
            {
                std::cout << "Test #" << (i+1) << std::endl;
                Sleep(10);
            };
        };
    };
};

int main()
{
    try
    {
      TST::MyAsyncAction1 oBj;
    }
    catch (const TST::Exception& excpt)
    {
        std::wcerr << excpt.What();
    };
};

Синтаксических ошибок нет. Прочесал весь код, но и логических ошибок не нашел. Запускается и завершается нить корректно, сигнатура функции Call верная, механизм обработки исключений тоже правильный..
Вообщем, я пришел к выводу, что ошибок здесь нет, разве что одна потенциальная ошибка и двойное отрицание (я отметил комментариями)
Ваше мнение?
Заранее спасибо!

 Профиль  
                  
 
 Re: в чем все-таки ошибка?
Сообщение29.08.2012, 22:43 
Заслуженный участник


04/05/09
4587
ИМХО, второй комментарий и есть ошибка. CallBase подобъект может быть ещё не инициализирован к тому моменту, где вызывается виртуальный метод Call(). Вам может повезти, и основной поток успеет завершить инициализацию до момента использования, но может и не повезти.

 Профиль  
                  
 
 Re: в чем все-таки ошибка?
Сообщение29.08.2012, 22:52 
Заслуженный участник


28/04/09
1933
venco в сообщении #612405 писал(а):
CallBase подобъект может быть ещё не инициализирован к тому моменту, где вызывается виртуальный метод Call().
Так конструкторы базовых классов вызываются (вроде бы) в порядке упоминания этих классов в списке наследования, так что все в порядке.

 Профиль  
                  
 
 Re: в чем все-таки ошибка?
Сообщение29.08.2012, 22:59 
Заслуженный участник


04/05/09
4587
Да, но конструктор MyAsyncAction1, который, по идее, и должен в начале прописать новую таблицу виртуальных функций с MyAsyncAction1::Call() будет выполнен после конструктора AsyncActionBase. Т.е. вместо AsyncActionBase::Call() может вызваться CallBase::Call(), которого нет. Как следствие - attempt to call pure virtual function.

 Профиль  
                  
 
 Re: в чем все-таки ошибка?
Сообщение29.08.2012, 23:18 
Заслуженный участник


28/04/09
1933
venco
venco в сообщении #612408 писал(а):
конструктор MyAsyncAction1, который, по идее, и должен в начале прописать новую таблицу виртуальных функций с MyAsyncAction1::Call() будет выполнен после конструктора AsyncActionBase.
Точно! А чтобы убедиться в этом, можно вставить Sleep в конце конструктора AsyncActionBase.

 Профиль  
                  
 
 Re: в чем все-таки ошибка?
Сообщение30.08.2012, 00:39 
Аватара пользователя


20/03/12
23
Прям чувствовал, что весь подвох в конструкторе MyAsyncAction1... Мне казалось, что связывание происходит на этапе компиляции! Поэтому я посчитал, что к моменту вызова конструктора AsyncActionBase, таблица виртуальных методов MyAsyncAction1 будет уже связана.
EtCetera
Да, Sleep'ом удалось получить pure virtual function call =).
Спасибо, ребята!

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 6 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group