C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 Q&A
C++Builder Programming Q&A
[50476] Re:Re:[Q] TForm의 유효기간?
우리 [palindrome] 1661 읽음    2007-09-06 03:15
Form을 생성하면 당연히 메모리에 할당하고
종료시에 메모리에서 해제한다고해서 메모리를 memset() 처럼 깨끗하게 지우지는 않습니다.
그냥 내용은 그대로 다 존재하고 할당당했던 메모리 영역을
릴리즈해주는 것입니다. 다른 곳에서 할당하여 사용될 수 있도록만.
그러니 처음 Form의 포인터로 사용되었던 변수에
메모리 할당을 받았던 주소를 기억하고 있기때문에
그 주소로 가면 아직 다른 메로리 할당에 의해 할당되어값이 변경되지 않았다면
기존과 같이 값을 참조할 수 있습니다.
그래서 기본적으로 Form Close 부분에서

Action = caFree;

이것을 사용하려면 바로 뒤에 pForm 변수를 NULL 로 만들어야합니다.
여기서는 지역변수로 사용했지만 보통 전역변수로 Form 을 할당 받아
여기저시가 많이 사용하는 경우가 있는데 이경우에는
어떤놈이 Form을 Close하여 메모리를 릴리즈했는데
다른곳에서 이 Form 을 할당받은 변수로 다시 엑세스 하는 경우가 있습니다.
이럴때 access voilation 에러가 발생합니다.
이런경우에는 Close()함수 내부에

Action = caFree; 을 하기 전이나 바로뒤에 Form을 생성한 포인터 변수를
먼저 NULL로 해주어야합니다.
그리고 다른 곳에서 이 변수를 사용할 경우 항상
변수가 NULL인지 아닌지 확인후 사용해야합니다.

특히 쓰레드 같은 곳에서 Form을 access할 경우 이런 잘못을 많이하곤 합니다.

님같은 경우 ShowModal() 로 생성 후 값을 입력받고 싶어서 한다면
Close() 함수에 Action = caFree;를 사용하지 않는것이 좋습니다.
참/거짓 등의 정보많 받는다면 리턴값으로 받을 수 있어서 사용해도 상관없지만
Input Box 등을 넣어 스트링 등을 받아야할 경우
Action = caFree; 를 사용하는 것은 바람직하지 않습니다.
명시적으로 생성 후 값을 입력받고 다 사용후에 삭제하는 루틴을 넣는것이 좋습니다.

그럼 좋은하루되세요.



장성호 님이 쓰신 글 :
: FormClose이벤트에서 Action=caFree 하면 자동으로 free됩니다.
: 즉 delete하실 필요가 없습니다.
:
: 그렇지만 님과 같이 delete하더라도 access voilation이 나지는 않는데....
: 좀 이상하네요
:
: 빈프로젝트에 Form 2개만 넣어서 테스트 해보십시요
: 그럼 에러가 없을것입니다.
:
: 무슨 다른곳에서 Error가 나는것 아닌가 생각합니다.
:
: [추신]
: << OnClose에서 Action=caFree하고 또 delete하여도 Error가 나지 않는 이유 >>
:      (  caFree메가니즘 )
:
:
: 아래는 TForm의 조상인 TCustomForm의
: Close함수와 Release 함수, 그리고  CM_RELEASE메세지를 받아서 처리하는 함수의 VCL 코드입니다.
:
: //--------------------------------------------------------------
: procedure TCustomForm.CloseModal;
: var
:   CloseAction: TCloseAction;
: begin
:   try
:     CloseAction := caNone;
:     if CloseQuery then
:     begin
:       CloseAction := caHide;
:       DoClose(CloseAction);            //    OnClose이벤트 핸들러 호출
:     end;
:     case CloseAction of
:       caNone: ModalResult := 0;
:       caFree: Release;                    // CloseAction = caFree이면 Release호출
:     end;
:   except
:     ModalResult := 0;
:     Application.HandleException(Self);
:   end;
: end;
: //--------------------------------------------------------------
: procedure TCustomForm.Release;
: begin
:   PostMessage(Handle, CM_RELEASE, 0, 0);        //이부분에서 바로 release하지 않고 PostMessage합니다.
: end;
: //--------------------------------------------------------------
: procedure TCustomForm.CMRelease;
: begin
:   Free;                       //이부분에서 진짜로 release됩니다.
: end;
: //--------------------------------------------------------------
:
: 그런데 TCustomForm.Release함수에서  SendMessage가 아니고 PostMessage 입니다.
: 즉 곧바로 RELEASE되는것이 아니라 
: 현재 함수코드진행은 수행이 끝나고 즉 CloseModal함수가 끝나야 되구요
: 또한 ShowModal을 호출한곳에서 다음 코드가 있다면 그것이 수행이 끝날때까지
: 실제적으로 Handle은 release가 되지 않는것입니다.
: 님의  아래코드에서 delete가 호출된후에
: 다음 GetMessage가 호출되어야  CustomForm의 Handle이  CM_RELEASE 메세지를 받을수 있는데...
: 이미 delete에서 Handle이 없어졌으므로 CM_RELEASE 는 아무 의미가 없는 메세지가 되는것입니다.
:
:
: 아래와 같이 코딩하면 확실에 에러가 납니다.
:
: void __fastcall TForm1::Button1Click(TObject *Sender)
: {
:     Form2=new TForm2(this);
:     int rslt=Form2->ShowModal();
:     Application->ProcessMessages(); //이부분에서 CustomForm의 Handle이  CM_RELEASE 메세지를 받아 free됨
:    delete Form2; //이미 free된것을 또 다시  free하려고 함  --> 이경우 여기서 반드시 에러가 남
: }
: //---------------------------------------------------------------------------
:
: 왜냐하면 Application->ProcessMessages 함수에서
: TCustomForm.Release 에서 PostMessage한 메세지를
: GetMessage로 가져와서 처리하게때문입니다.
:
: [참고]
: Form2는 아마 전역 변수일것입니다.
:
: 님과 같이 코딩하실때는 가능하면
: TForm2 *frm=new TForm2(this); //이렇게 포인터변수를 선언해서 쓰는것이 안전합니다.
:
:
: 말이 많이 길어졌네요
:
: 결론적으로
: 님이 적어주신 코드에서는 직접적인 에러의 원인이 없습니다.
: 하지만 Action=caFree 나 delete둘중 하나만 쓰세요
:
: 그럼...
:
:
: 땅주인 님이 쓰신 글 :
: : 메인 윈도우에서 여는 서브 윈도우의 Close Event에서 가지고 있던 Resource를 자동 해제하려고 이렇게 썼습니다.
: :
: : void __fastcall TForm2::FormClose(TObject *Sender, TCloseAction &Action)
: : {
: :     Action = caFree;
: : }
: :
: : 근데, 메인 윈도우에서 Form2를 열고, 닫은 후에도 Form2의 변수 값에 접근할 수 있고,
: : 그런데.. delete는 할 수 없고.. 이게 어찌된 영문 인 지?
: :
: : [ Main Window의 Button Event ]
: :
: : void __fastcall TForm1::Button1Click(TObject *Sender)
: : {
: :     TForm2 *pForm = new TForm2(this);
: :
: :     pForm->ShowModal(); // 모달 상자로 열었음.
: :
: :     k =pForm->m_ikk;         // Form2의 멤버에 접근이 가능함.
: :
: :     delete pForm;              // Access Violation나옴.
: : }
: :
: : 변수값은 Access가능하고, Form를 delete할 때는 에러나고.. 속시원히 해결을 좀?
: : Action = caFree이면 폼이 가지고 있던 모든 리소스도 해제되는 것 아닌가요?
: :
: : 그리고, 사실 다른 곳에서 썼던 스크립트는 위와 비슷한 코드인데.. delete pForm에서 전혀 에러를 내지
: : 않고 잘 나갑니다. 가끔 프로그램이 Access Violation을 내는데..여긴 지 아닌 지는 잘 모르겠지만..
: : 어쨌거나 잘 돌아가는 경우가 더 많다는 것이죠.. 좀 헷갈려서..... 속시원히 해결해 주실분 부탁해요..
: :
: : 감사합니다.

+ -

관련 글 리스트
50472 [Q] TForm의 유효기간? 땅주인 1344 2007/09/05
50474     Re:[Q] TForm의 유효기간? 장성호 1570 2007/09/05
50476         Re:Re:[Q] TForm의 유효기간? 우리 1661 2007/09/06
50480             Thanks..Thanks..Thanks... 땅주인 1381 2007/09/06
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.