Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Недостатки обычных – «неумных» – указателей.




void MyFunction()

{

double *Arr;

int k=0;

Arr[k]=1.23; // ошибка: Arr не инициализирован, не выд. память

int Num=100;

Arr = new double [Num];

Arr[k]=1.23; // нет ошибки

Arr=0;     // нет ошибки времени выполнения, но память потеряна

Arr[5]=0; // ошибка: Arr недействителен

Arr = new double [Num];

double *Arr2;

Arr2=Arr; // нет ошибки

delete [] Arr;

Arr2[5]=0; // ошибка: Arr2 указывает на уже освобожденную память

delete [] Arr2; // ошибка: повторное освобождение памяти

// ...

Arr = new double [Num];

Arr++;

delete Arr; // ошибка: Arr указывает не на начало выделенного блока памяти в куче

// ...

Arr = new double [Num];

// …

return; // забыли освободить память

}

 

Показать те же проблемы на примере класса.

Чего бы хотелось? Хотелось бы, чтобы эти ошибки невозможно было совершить или чтобы мы получали сообщение об ошибке уже на этапе компиляции (разработки) и чтобы это сообщение было наглядным и однозначно указывало на место ошибки.

 

template<class T>

class SmartPtr

{

private:

T* m_pPtr;

SmartPtr & operator=(const SmartPtr & rPtr) {}

public:

SmartPtr(T* pPtr)

{

        ASSERT(pPtr != NULL);

   m_pPtr = pPtr; 

/* Если значение выражения макроса истинно, то состояние ошибки не возникает, а в противном случае выполнение программы прерывается с выводом информации о месте ошибки. Макрос ASSERT отлавливает ошибки только в том случае, если используются отладочные версии библиотеки MFC. В противном случае макрос «не работает» и не продуцирует никакого программного кода. Если же Вы хотите, чтобы выражение вычислялось в обеих версиях программы – отладочной и окончательной, – используйте макрос VERIFY вместо ASSERT. В отладочной версии макрос VERIFY ведет себя так же, как и макрос ASSERT. В окончательной версии макрос VERIFY  вычисляет выражение, но не проверяет результат*/

}

~SmartPtr()

{

       if(m_pPtr) delete m_pPtr;

}

T* operator->() const

{

  ASSERT(m_pPtr != NULL);       

  return m_pPtr;

}

};

class CMyClass

{

  int Value;

  public:

              CMyClass() {TRACE("Enter in CMyClass::CMyClass()"); Value=123;}

              ~CMyClass() {TRACE("Enter in CMyClass::~CMyClass()");}

              int GetValue(){return Value;}

};

 

void MyFunc()

{

  /* SmartPtr <CMyClass> Obj; ошибка: нет соответствующего конструктора

 по умолчанию */

  SmartPtr <CMyClass> Obj(new CMyClass);

  TRACE("Obj->GetValue()=%d\n",Obj->GetValue());

  CMyClass StatObj;

  //Obj=&StatObj; //ошибка: невозможно получить доступ к защ. члену

  /*

  error C2248: 'SmartPtr<T>::operator =' : cannot access private member

  declared in class 'SmartPtr<T>'

  */

  SmartPtr <CMyClass> Obj2(new CMyClass);

  // Obj=Obj2;//ошибка: невозможно получить доступ к защ. члену

  SmartPtr <CMyClass> Obj3(&StatObj); /* возможно и это недостаток реализации

  интеллектуального указателя*/

}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])

{

  if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))

  {

              _tprintf(_T("Fatal Error: MFC initialization failed\n"));

              return 1;

  }

  MyFunc();

  _getch();

  return 0;

}


Библиотека ATL среды Visual C++ содержит определения интеллектуальных указателей, используемых в клиентских приложениях, импортирующих библиотеки типов, для доступа к сервисам СОМ-серверов. Это шаблонные классы CComPtr и _com_ptr_t, описания которых можно найти в MSDN, а примеры использования – в данной работе (см. раздел «Применение интеллектуальных указателей для доступа к серверам»).


Управление формой курсора мыши

В простейшем случае, если надо показать «песочные часы», можно поступить так:

BeginWaitCursor();

// долго с чем-то возимся

  EndWaitCursor();

Другие подробности – в MSDN, причем совсем задаром.

 

Как выйти из длительного цикла

Если какая-либо функция приложения выполняется длительное время, полезно предоставить пользователю возможность ее остановки. Если приложение однопоточное, то можно написать примерно такую функцию:

void CMyView::ProcessMessages()

{

MSG msg;

       while(::PeekMessage(&msg,NULL,0,0,PM_REMOVE))

       {

                   ::TranslateMessage(&msg);

                   ::DispatchMessage(&msg);

       }

}

 

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

Если же приложение многопоточное, то при нажатии пользователем кнопки завершения приложения (в системном меню – правом верхнем углу главного окна приложения) может появиться сообщение об ошибке. Ваше приложение может быть многопоточным даже и в том случае, если Вы и не создаете «в лоб» дополнительный поток, например, просто строите приложение на основе классов CRichEditCtrlItem и CRichEditView. В подобном случае можно поступить следующим образом.

Перекройте виртуальную функцию WindowProc(), например, класса вида, такой реализацией:

LRESULT CMyView::WindowProc(UINT message, WPARAM wParam,

                                                           LPARAM  lParam)

{

       Stop=(message==257)&(wParam==27);

       return CView::WindowProc(message, wParam, lParam);

}

 

В ней магическое число 27 – это код клавиши Escape, а Stop – переменная булевского типа, которую Вы описали в своем же классе CMyView и изначально присвоили ей значение false. Функция WindowProc() обрабатывает все сообщения, которые Windows посылает, в данном примере, окну вида приложения. Следовательно, если пользователь нажмет клавишу Escape, то переменная Stop примет значение true, которое можно проанализировать в длительном цикле и выйти из него. Не забудьте в этом цикле вызывать функцию ProcessMessages.

 










Последнее изменение этой страницы: 2018-04-12; просмотров: 407.

stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...