2 C++ namespace 별칭 만들기, 줄여쓰기 #
namespace zelon = std;
int main()
{
zelon::cout << "selfishef" << zelon::endl;
return 0;
}
위와 같이 std 를 zelon 으로 해서 마치 std 를 zelon 이라는 이름으로 쓸 수 있다. namespace fs = boost::filesystem; 처럼 줄여서 쓸 수도 있을 것이다.
3 C++ 다음 표준인 c++0x 표준에 관한 wish list #
5.1 vertical tab 수직탭 #
문자열 중에 확장 문자열이라는 게 있다. 대표적으로 \n 같은 경우인데 일종의 정해진 규약이다. 이 중에 수직탭이라는 게 있는데 \v 로 표현된다. C 언어 펀더멘탈 책을 보던 중 궁금증이 들어서 출력을 해보니 윈도우 콘솔 상에서는 이상한 특수문자를 하나 출력해주고 만다. 하지만 리눅스 콘솔에서 출력해보니 세로로 한 칸 내려가버린다. 즉 다음과 같은 결과를 보여준다.
"aaa\vbbb" 를 출력
aaa
bbb
5.2.1 실수하기 쉬운 생성자가 많은 부하를 일으키는 경우 #
struct Array
{
int a[1000];
};
struct zelon
{
zelon() : arr()
{
}
Array arr;
};
zelon a;
cout << a.arr.a[0] <<endl;
위의 코드에서 zelon() : arr() 의 코드는 arr 의 멤버변수를 모두 0 으로 초기화한다. 초기화하는 만큼 시간이 더 걸린다.
5.2.2 윈도우에서 eclipse + mingW 로 컴파일 환경 구축하기 #
#include <limits>
double dMax = numeric_limits<double>::max();
ifstream, ofstream 의 인스턴스를 생성했다면, 제대로 생성했는지는 if ( fout ) 등으로 알 수 있다..
DWORD WINAPI WorkerThread(LPVOID);
bool finish = false;
int main(){
DWORD dwID;
HANDLE h = CreateThread(NULL,0,WorkerThread,NULL,0,&dwID);
Sleep(1000);
// Woker Thread가 종료하도록 유도
finish = true;
// Thread 종료 대기
WaitForSingleObject(h,INFINITE);
CloseHandle(h);
return 0;
}
DWORD WINAPI WorkerThread(LPVOID){
int i = 0;
while(!finish){
++i;
}
return 0;
위의 소스를 Debug, Release 둘다에서 돌려보고, bool finish 를 volatile bool finish 로 바꾸어서 같은 방법으로 테스트해보자.
5.8 C++ 의 함수자(functor) 예제 #
string 을 템플릿 인자로 받는 컨테이너에 대한 간단한 출력 함수자.
class PrintString
{
public:
void operator()(string & a)
{
cout << a << endl;
}
};
5.9.1 최대한 new, delete 는 자제한다 #
new, delete 는 최대한 자제하면서, 될 수 있으면 stack 에 변수를 만든다. 어쩔 수 없이, new 를 쓰게 되면 최소한 하나의 delete 코드는 바로 만들고, 시간적 여유가 된다면 memorypool 을 이용한다.
5.10.1 실행 중 purevirt.c 에서 에러날 때 #
void __cdecl _purecall(
void
)
{
if(__pPurecall)
{
__pPurecall();
/* shouldn't return, but if it does, we drop back to
default behaviour
*/
}
_amsg_exit(_RT_PUREVIRT);
}
의 __pPurecall() 에서 에러가 난다면 순수 가상 함수를 제대로 구현하지 않았기 때문이다. 원래 캄파일이 안되어야하나
PreCompiled Header 나 다른 기타 이유로 제대로 빌드되지 않았기 때문이다. 일단 다시 빌드 해보고 빌드되는 파일이 없으면 리빌드를 해보자.
5.10.2 VC++ 에서 상속을 이용하던 중 _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) assert 가 뜰 때 #
5.10.5 템플릿에서 typename 과 class 의 차이점 #
typename T::SubType *ptr;
과 같은 경우 typename 이 없으면 T::
SubType 이 타입인지, T 의 static member 인지 알 수 없기 때문이다.
5.10.6.1 already defined in XXX #
Visual Studio 에서 작업 중이라면 라이브러리와의 충돌일 수 있다. 라이브러리를 컴파일 할 때 컴파일 옵션에서 Runtime Library 의 종류가 현재 프로젝트의 종류가 같은지 체크해본다. 예를 들어 라이브러리의 컴파일 옵션이 'Multi-threaded Debug DLL' 이면 그 라이브러리 파일을 이용하는 현재 프로젝트의 컴파일 옵션도 'Multi-threaded Debug DLL' 이어야 한다.
| static_cast | C 의 캐스트와 가까운 변환. 하지만, 상속 트리와 상관없이 변환하려면 컴파일 에러 |
| const_cast | 상수를 비상수로 만들거나 반대의 작업을 한다. 이것을 쓴다는 것은 디자인에 문제가 있다는 증거 |
| reinterpret_cast | C 의 캐스트와 같은 변환. 최대한 자제할 것 |
| dynamic_cast | 형 변환이 가능한지를 런타임 시에 판단한다. 가능하다면 새로운 포인터를 반환. 실패하면 NULL 반환. RTI 가 켜져있어야 한다. |
5.10.11 메모리 내용을 통한 메모리 상태 #
0xCCCCCCCC
초기화 하지 않은 지역변수
0xCDCDCDCD
힙에 할당된 메모리다.그러나 초기화 되지 않았다.
0xDDDDDDDD or 0xFEEEFEEE
힙에서 Free된 메모리이다. 그것을 사용할 때
0xFDFDFDFD
할당한 것을 벗어난 heap의 공간을 사용할 시
5.10.13 MFC 에서 특정 메모리 할당 순서에 브레이크 포인트 걸기 #
5.10.17 함수 호출에 따른 생각할 것들 #
Method Calling Convention
5.10.18 == 와 = 의 실수를 방지하는 작은 팁 #
if ( obj == NULL ) 을 쓰는 대신에 if ( NULL == obj ) 를 쓰는 습관을 들이자. 실수로 if ( NULL = obj ) 가 되면 대입(obj 를 NULL 에 넣기)을 할 수 없기 때문에 컴파일 에러가 난다.
ps : 요즘 좋은 컴파일러들은 저런 실수는 알아서 찾아주더라만은;;
classA *pA = new classA;
if(pA != NULL)
{
delete pA;
pA = NULL; // 요부분을 한번 삽입해 줘보세요....
}
가끔 주석단부분 안써주었을때, 에러 발생하는데 이거해주면 안나더라구요...메모리부족에러인지는 정확히 모르겠구요....
일단 프로그램은 메모리오류가 나면서 종료되는 경우도 있죠.
그걸 막기 위해서는 exception 처리를 하셔야죠
new가 실패할 경우 catch하여 적절히 처리하면 되겠지만.
이 부분을 어떻게 처리할지는 전적으로 프로그래머의 책임입니다.
보통 new가 실패하면 프로그램의 기능이 유명무실해지는 경우가
많기 때문에 메모리를 확보하라는 메세지와 함께 프로그램을 중단
한다고들 하더군요.
1. (STL에서) 재할당 되거나 기타 이유로 무효화된 iterator 를 엑세스 <- 압도적으로 많음
2. virtual table 을 가지고 있는 객체의 포인터 캐스팅 실수 - reinterpet_cast 를 사용한다던가 -
3. new [] 로 할당해놓고 delete 로 해제하는등의 할당 연산자 불일치.
-- from gpgstudy
아니면 new 해서 100 바이트를 할당해놓고, 101 바이트에 다가 뭔가를 썼다던지 그럴 경우도 있음.
win32 의
ZeroMemory() 나 memset() 을 쓸 때는 구조체등을 함부로 쓰지 않는다. 그 구조체안에 std:string 등 내부적으로 어떤 값을 다시 가지고 있을 경우 위험하다. 단지 메모리를 0 으로 채워주는 것은 위험하다는 것이다.
| 0xCDCDCDCD | Allocated in heap, but not initialized |
| 0xDDDDDDDD | Released heap memory |
| 0xFDFDFDFD | "NoMansLand" fences automatically placed at boundary of heap memory. Should never be overwritten. If you do overwrite one, you're probably walking off the end of an array |
| 0xCCCCCCCC | Allocated on stack, but not initialized |
5.10.24 클래스에서 private 와 public 의 용법에 대한 대표적인 예제 #
위와 같은 코드는 month 가 절대로 12 를 넘을 수 없게 보장해준다. 왜냐하면 m_month 에 값을 넣어줄 때 m_month 에는 절대로(private 이기 때문에) 외부에서는 넣어줄 수 없고, public 함수인
SetDate() 를 통해서만 할 수 있기 때문이다. 하지만
SetDate() 에서는 if 문을 통해 month 값을 검사해주므로 m_month 에는 12 를 넘는 값을 넣을 수 없게 보장!! 해준다.
이 예제 코드를 통해 왜 private 을 쓰는지 느낄 수 있을 것이다.
5.10.25 Visual C++ 6.0 에서 . 찍어도 인텔리 센스가 작동 안 할 때 #
꼭(!!) 프로젝트를 닫고, 폴더 내의 .ncb 와 .opt 파일을 지운 후 다시 프로젝트를 로딩한다.
5.10.26 특정 변수의 min, max 값 구하기 #
#include <limits>
// int의 경우.
int minInt = numeric_limits<int>::min();
int maxInt = numeric_limits<int>::max();
시간나면 해석해보기;;
- 윈도우의 VC++ 의 경우 stdafx.h 에 거의 변하지 않는 헤더들을 모아놓으면 좋다.
5.10.28 Code Beautifier #
sf.net 에서 astyle 을 검색해보자.
Insert Rhaon File Header:
/* ------------------------------------------------------------------------
*
* Copyright %YEAR% by Rhaon Ent.
*
* %FILE_BASE%.%FILE_EXT%
*
* %YEAR%.%MONTH%.%DAY% Kim Jinwook
*
* ------------------------------------------------------------------------
*/
Insert .h Base:
#pragma once
class C%FILE_BASE%
{
public:
C%FILE_BASE%();
~C%FILE_BASE%();
};
Insert .cpp Base:
#include "stdafx.h"
#include "%FILE_BASE%.h"
C%FILE_BASE%::C%FILE_BASE%()
{
}
C%FILE_BASE%::~C%FILE_BASE%()
{
}
ifstream fin("original.zip", ios_base::_Nocreate | ios_base::binary);
fin.seekg(0, ios_base::end);
int endPosition = fin.tellg();
char * pData = new char[endPosition];
char * pRecv = new char[endPosition];
fin.seekg(0, ios_base::beg);
fin.read(pData, endPosition);
fin.close();
ofstream fout("target.zip", ios_base::binary);
fout.write(pRecv, endPosition);
fout.close();
5.10.32 random 한 문자열 생성 함수 #
std::string GetRandomString(int iMaxLength, int iMinLength = 4)
{
// random 한 길이를 정한다.
int iLen = (rand() % (iMaxLength - iMinLength + 1)) + iMinLength;
int i = 0;
char iTempChar = 0;
std::string strRet = "";
for ( i = 0; i<iLen; ++i)
{
iTempChar = (rand() % ( 90 - 65 + 1)) + 65;
strRet.push_back(iTempChar);
}
return strRet;
}
mpatrol 나 valgrind와 같은 메모리 디버거를 사용하면
어느 지점에서 오버플로우나 잘못된 주소의 참조가 일어 나는지 찾는데 도움을 얻을 수 있습니다.
5.12 함수 호출에 따른 생각할 것들 #
Method Calling Convention
5.13 == 와 = 의 실수를 방지하는 작은 팁 #
if ( obj == NULL ) 을 쓰는 대신에 if ( NULL == obj ) 를 쓰는 습관을 들이자. 실수로 if ( NULL = obj ) 가 되면 대입(obj 를 NULL 에 넣기)을 할 수 없기 때문에 컴>
파일 에러가 난다.
ps : 요즘 좋은 컴파일러들은 저런 실수는 알아서 찾아주더라만은;;
5.14 클래스에서 private 와 public 의 용법에 대한 대표적인 예제 #
내가 가장 좋아하는 예제이다.
class Date
{
public:
void
SetDate(int year, int month, int day)
{
if ( month > 12 ) return;
m_year = year;
m_month = month;
m_day = day;
}
private:
int m_year;
int m_month;
int m_day;
};
위와 같은 코드는 month 가 절대로 12 를 넘을 수 없게 보장해준다. 왜냐하면 m_month 에 값을 넣어줄 때 m_month 에는 절대로(private 이기 때문에) 외부에서는 넣어줄
수 없고, public 함수인
SetDate() 를 통해서만 할 수 있기 때문이다. 하지만
SetDate() 에서는 if 문을 통해 month 값을 검사해주므로 m_month 에는 12 를 넘는 값을 >
넣을 수 없게 보장!! 해준다.
이 예제 코드를 통해 왜 private 을 쓰는지 느낄 수 있을 것이다.
5.15 Visual C++ 6.0 에서 . 찍어도 인텔리 센스가 작동 안 할 때 #
꼭(!!) 프로젝트를 닫고, 폴더 내의 .ncb 와 .opt 파일을 지운 후 다시 프로젝트를 로딩한다.
5.16 divide zero, access violation 을 try, catch 로 구분하기 #
일단 의심나는 곳을 try 로 감싸고 catch ( ... ) 으로 하면 일단 잡히기는 한다. 하지만 정보를 좀 더 얻고 싶다면 msdn 에서 다음을 참고하면 좋다.
_set_se_translator()
새로운 Exception class 를 하나 만들어서 좀 더 많은 정보를 얻어낼 수 있다. 단, win32 에서만 사용가능.
5.17 이상하게도 자신의 멤버변수에 접근을 못할 때 #
디버그 모드에서도 F10 으로 한단계 한단계 따라가는데
if ( this->m_aIntMember == 10 )
과 같은 구문에서도 오류가 난다. 황당한 경우다. 하지만 이 경우에는 객체 자체가 잘못되었을 가능성이 높다.
위와 같이 쓰레기 값으로부터 멤버 함수를 호출할 수도 있을 것이다.
아니면 return address 를 덮어썼을 경우에 발생한다.
그 안에서 메모리를 잘못 덮어쓰지 않았나 검사해본다. strcpy 나 배열등...
예를 들어 다음과 같은 멤버 함수에서 꼭 에러가 난다면,
void A::Func()
{
if ( m_age < 0 )
{
cout << m_age;
}
}
A::Func() 를 부르는 코드에서 A 의 인스턴스가 제대로 생성된 것인지를 살펴봐야한다. 예를 들면
int main()
{
A * pA = NULL;
pA->Func();
// 혹은
A aArray[10];
aArray[100].Func();
}
위와 같은 실수를 할 수가 있다. 물론 저렇게 명백히 아래위로 코드가 적힌 경우야 실수할 일도 거의 없겠지만... 다른데서 포인터를 받아오고, 다양한 선언을 하고 조금 코드가 복잡하면 문제가 될 수 있다.
즉, 자신의 멤버 변수에도 접근을 못한다면, 그 객체 자체를 의심해 보아야한다.