'CS/C/C++'에 해당되는 글 24건

  1. 2010.01.26 Reference to Pointer
  2. 2009.12.11 WebKit Smart Pointer (RefPtr, PassRefPtr)
  3. 2009.11.06 [C++] Virtual Function에 Access
  4. 2009.10.14 [C/C++] 컴파일 타임에 ASSERT 시키기
  5. 2009.09.30 [C/C++] Hamming weight
  6. 2009.09.17 [C/C++] enum 내부에서의 macro 사용
  7. 2009.09.10 [C/C++] Copy constructor, Copy assignment
  8. 2009.09.10 [C/C++] const
  9. 2009.09.06 [C/C++] Shift 연산자
  10. 2009.09.03 [C++] Class Member Function 의 저장과 호출
  11. 2009.09.01 [Win32] WM_COMMAND
  12. 2009.08.14 [C/C++] _strdup
  13. 2009.08.03 [MFC/C++] GetSafeHwnd()
  14. 2009.07.30 [C++] 내부 클래스에서 외부 클래스의 Function에 접근
  15. 2009.04.07 [C++] Static member initialization
  16. 2009.02.28 [C++] 상속
  17. 2009.01.19 [C++] casting
  18. 2009.01.18 [C++] 연산자 우선순위
  19. 2009.01.18 [C/C++] Pointers
  20. 2009.01.18 [C++] Enumerations
  21. 2009.01.18 [C++] Misc.
  22. 2009.01.18 [C++] Virtual Function
  23. 2009.01.18 [C++] Representation & Class definition
  24. 2009.01.18 [C++] C 프로그래머에게의 제안

Reference to Pointer

CS/C/C++ 2010. 1. 26. 03:51
일단 간단한 예제는...
void set_p(int* p, int val)   { p = new int(val); }
void set_pr(int*& p, int val) { p = new int(val); }

int main(void)
{
    int *a;

    // set_p(a, 10);
    set_pr(a, 10);
    cout << *a << endl;    

    // ...

    return 0;
}

WebKit Code에서 사용된 예,
if (JSGlobalObject*& headObject = head()) {
        d()->prev = headObject;
        d()->next = headObject->d()->next;
        headObject->d()->next->d()->prev = this;
        headObject->d()->next = this;
} else {
        headObject = d()->next = d()->prev = this;
}
head()가 NULL인 경우 처리가 참 깔끔하게 된다...
:

WebKit Smart Pointer (RefPtr, PassRefPtr)

CS/C/C++ 2009. 12. 11. 05:52
참조 :
1. http://webkit.org/coding/RefPtr.html
2. WebKit Source Code

RefPtr
Simple smart pointer.

생성자 및 소멸자
template <typename T>
RefPtr<T>::RefPtr() : m_ptr(0)
{ }

template <typename T>
RefPtr<T>::RefPtr(T* ptr) : m_ptr(ptr)
{
    if (ptr) ptr->ref();
}

template <typename T>
RefPtr<T>::~RefPtr()
{
    if (T* ptr = m_ptr) ptr->deref();
}

복사 생성자
template <typename T>
RefPtr<T>::RefPtr(const RefPtr& o) : m_ptr(o.m_ptr)
{
    if (T* ptr = m_ptr) ptr->ref();
}

대입 연산자
template <typename T> inline
RefPtr<T>& RefPtr<T>::operator=(T* optr)
{
    if (optr)
        optr->ref();
    T* ptr = m_ptr;
    m_ptr = optr;
    if (ptr)
        ptr->deref();
    return *this;
}

template <typename T> inline
RefPtr<T>& RefPtr<T>::operator=(const RefPtr<T>& o)
{
    T* optr = o.get();
    if (optr)
        optr->ref();
    T* ptr = m_ptr;
    m_ptr = optr;
    if (ptr)
        ptr->deref();
    return *this;
}

template <typename T> inline
RefPtr<T>& RefPtr<T>::operator=(const PassRefPtr<T>& o)
{
    T* ptr = m_ptr;
    m_ptr = o.releaseRef();
    if (ptr)
        ptr->deref();
    return *this;
}

사용 예
// example, not preferred style
class Document
{
    // ...
    RefPtr<Title> m_title;
}

void Document::setTitle(Title* title)
{
    m_title = title;
}

// example, not preferred style
RefPtr<Node> createSpecialNode()
{
    RefPtr<Node> a = new Node;
    a->setSpecial(true);
    return a;
}

RefPtr<Node> b = createSpecialNode();



PassRefPtr
전달시 Ownership을 포기한다.
Recommended only for function argument and result types, copying arguments into RefPtr local variables.

void derefIfNotNull(T* ptr)
{
    if (UNLIKELY(ptr != 0))
        ptr->deref();
}

template <typename T>
T* PassRefPtr<T>::releaseRef() const
{
    T* tmp = m_ptr;
    m_ptr = 0;
    return tmp;
}

생성자 및 소멸자
template <typename T>
PassRefPtr<T>::PassRefPtr() : m_ptr(0)
{ }


template <typename T>
PassRefPtr<T>::PassRefPtr(T* ptr) : m_ptr(ptr)
{
    if (ptr) ptr->ref();
}


template <typename T>
PassRefPtr<T>::~PassRefPtr()
{
    derefIfNotNull<T>(m_ptr);
}


복사 생성자
template <typename T>
PassRefPtr<T>::PassRefPtr(const PassRefPtr& o) : m_ptr(o.releaseRef())
{}


대입 연산자
template <typename T> inline
PassRefPtr<T>& PassRefPtr<T>::operator=(T* optr)
{
    if (optr)
        optr->ref();
    T* ptr = m_ptr;
    m_ptr = optr;
    if (ptr)
        ptr->deref();
    return *this;
}

template <typename T> inline
PassRefPtr<T>& PassRefPtr<T>::operator=(const PassRefPtr<T>& ref)
{
    T* ptr = m_ptr;
    m_ptr = ref.releaseRef();
    if (ptr)
        ptr->deref();
    return *this;
}


사용 예
// example, not preferred style
PassRefPtr<Node> createSpecialNode()
{
    PassRefPtr<Node> a = new Node;
    a->setSpecial(true);
    return a;
}

RefPtr<Node> b = createSpecialNode();

WebKit에서는 모든 경우에 RefPtr을 사용하기를 권장한다. 따라서 위의 경우처럼 ownership을 전달하고자 하는 경우
// example, assuming new Node starts with reference count 0
PassRefPtr<Node> createSpecialNode()
{
    RefPtr<Node> a = new Node;
    a->setSpecial(true);
    return a.release();
}

RefPtr<Node> b = createSpecialNode();




adoptRef
Reference count의 조작 없이 생성된 객체를 전달할 수 있게 한다. PassRefPtr의 friend로 되어있다.

template <typename T>
PassRefPtr<T>::PassRefPtr(T* ptr, bool) : m_ptr(ptr)
{ }

template <typename T> inline PassRefPtr<T> adoptRef(T* p)
{
    return PassRefPtr<T>(p, true);
}

사용 예
// preferred style
PassRefPtr<Node> Node::create()
{
    return adoptRef(new Node);
}
RefPtr<Node> e = Node::create();

// preferred style
PassRefPtr<Node> createSpecialNode()
{
    RefPtr<Node> a = Node::create();
    a->setCreated(true);
    return a.release();
}
RefPtr<Node> b = createSpecialNode();



OwnPtr, PassOwnPtr
RefPtr, PassRefPtr은 RefCounted에서 상속받은 클래스에만 적용할 수 있는 반면, OwnPtr, PassOwnPtr은 pointer type이나 pointed-to type을 취할 수 있다.
복사 생성자를 보면 인자로 std::auto_ptr을 받는데... 그렇다면 결국 패싱할때 소유권을 넘긴다는 말인데... 흠... 음... 흠... 좀더 살펴 봐야 겠다.

template <typename T>
struct RemovePointer {
    typedef T Type;
};

template <typename T>
struct RemovePointer<T*> {
    typedef T Type;
};

template <typename T> class OwnPtr : public Noncopyable
{
public:
    typedef typename RemovePointer<T>::Type ValueType;
    typedef ValueType* PtrType;   
    // ...

private:
    PtrType m_ptr;
};

생성자 및 소멸자
template typename<T> explicit
OwnPtr<T>::OwnPtr(PtrType ptr = 0) : m_ptr(ptr)
{ }

template typename<T>
OwnPtr<T>::~OwnPtr()
{
    deleteOwnedPtr(m_ptr);
}

복사 생성자
template typename<T>
OwnPtr<T>::OwnPtr(std::auto_ptr<ValueType> autoPtr) : m_ptr(autoPtr.release())
{ }

대입 연산자
template <typename T> inline
OwnPtr<T>& OwnPtr<T>::operator=(const PassOwnPtr<T>& o)

{
    T* ptr = m_ptr;
    m_ptr = o.release();
    if (ptr)
        deleteOwnedPtr(ptr);
    return *this;
}

:

[C++] Virtual Function에 Access

CS/C/C++ 2009. 11. 6. 21:13
WebKit Source에 보면
void* vptr() { return * reinterpret_cast<void**>(this); }
요런 함수가 정의되어 있다. 그림으로 나타내 보면,



결국 vptr()을 통해서 해당 virtual function에 직접 access 가능 하다.

실제 사용은,
// ...
if (value.isCell() && (value.asCell()->vptr() == globaData.jsFunctionVPtr)
// ...
struct VPtrSet {
    VPtrSet();
    
    void* jsArrayVPtr;
    void* jsByteArrayVPtr;
    void* jsStringVPtr;
    void* jsFunctionVPtr;
};
요렇게 쓰인다.
:

[C/C++] 컴파일 타임에 ASSERT 시키기

CS/C/C++ 2009. 10. 14. 01:26
원문 : WebKit JavaScriptCore

어떤 클래스의 크기를 제한 할 경우, 컴파일 타임에 클래스 크기를 확인하는 코드.
// tunable parameters
template<size_t bytesPerWord> struct CellSize;

// cell size needs to be a power of two for certain optimizations in collector.cpp
template<> struct CellSize<sizeof(uint32_t)> { static const size_t m_value = 64; };
template<> struct CellSize<sizeof(uint64_t)> { static const size_t m_value = 64; };

const size_t MINIMUM_CELL_SIZE = CellSize<sizeof(void*)>::m_value;
const size_t CELL_ARRAY_LENGTH = (MINIMUM_CELL_SIZE / sizeof(double)) + \
	(MINIMUM_CELL_SIZE % sizeof(double) != 0 ? sizeof(double) : 0);
const size_t CELL_SIZE = CELL_ARRAY_LENGTH * sizeof(double);

#define COMPILE_ASSERT(exp, name) typedef int dummy##name [(exp) ? 1 : -1]
#define ASSERT_CLASS_FITS_IN_CELL(class) \
	COMPILE_ASSERT(sizeof(class) <= CELL_SIZE, class_fits_in_cell)

만약 클래스 크기가 CELL_SIZE보다큰 경우, Compile time error가 발생하게 된다.

error : size of array 'dummyclass_fits_in_cell' is negative.

아, 핵심은

#define COMPILE_ASSERT(exp, name) typedef int dummy##name [(exp) ? 1 : -1]

라는 거죠...
:

[C/C++] Hamming weight

CS/C/C++ 2009. 9. 30. 16:14
원문 : Xen source code
참고 : http://en.wikipedia.org/wiki/Hamming_weight

  
static inline unsigned int generic_hweight32(unsigned int w)
{
    unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
    res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
    res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
    res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
    return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
}

static inline unsigned int generic_hweight16(unsigned int w)
{
    unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
    res = (res & 0x3333) + ((res >> 2) & 0x3333);
    res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
    return (res & 0x00FF) + ((res >> 8) & 0x00FF);
}

static inline unsigned int generic_hweight8(unsigned int w)
{
    unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
    res = (res & 0x33) + ((res >> 2) & 0x33);
    return (res & 0x0F) + ((res >> 4) & 0x0F);
}

static inline unsigned long generic_hweight64(__u64 w)
{
#if BITS_PER_LONG < 64
    return generic_hweight32((unsigned int)(w >> 32)) +
        generic_hweight32((unsigned int)w);
#else
    u64 res;
    res = (w & 0x5555555555555555ul) + ((w >> 1) & 0x5555555555555555ul);
    res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
    res = (res & 0x0F0F0F0F0F0F0F0Ful) + ((res >> 4) & 0x0F0F0F0F0F0F0F0Ful);
    res = (res & 0x00FF00FF00FF00FFul) + ((res >> 8) & 0x00FF00FF00FF00FFul);
    res = (res & 0x0000FFFF0000FFFFul) + ((res >> 16) & 0x0000FFFF0000FFFFul);
    return (res & 0x00000000FFFFFFFFul) + ((res >> 32) & 0x00000000FFFFFFFFul);
#endif
}
:

[C/C++] enum 내부에서의 macro 사용

CS/C/C++ 2009. 9. 17. 19:38
# 소스 : WebKit JavascriptCore

#define FOR_EACH_OPCODE_ID(macro) \
    macro(op_enter, 1) \
    macro(op_enter_with_activation, 2)	\
    macro(op_init_arguments, 1) \
    macro(op_create_arguments, 1) \
    macro(op_convert_this, 2) \
    \
    macro(op_new_object, 2) \
    macro(op_new_array, 4) \
    macro(op_new_regexp, 3) \
    macro(op_mov, 3) \
    \
    macro(op_end, 2)

#define OPCODE_ID_ENUM(opcode, length) opcode,
typedef enum { FOR_EACH_OPCODE_ID(OPCODE_ID_ENUM) } OpcodeID;
#undef OPCODE_ID_ENUM

const int numOpcodeIDs = op_end + 1;

#define OPCODE_ID_LENGTHS(id, length) const int id##_length = length;
FOR_EACH_OPCODE_ID(OPCODE_ID_LENGTHS);
#undef OPCODE_ID_LENGTHS
    
#define OPCODE_LENGTH(opcode) opcode##_length

#define OPCODE_ID_LENGTH_MAP(opcode, length) length,
const int opcodeLengths[numOpcodeIDs] = {FOR_EACH_OPCODE_ID(OPCODE_ID_LENGTH_MAP)};
#undef OPCODE_ID_LENGTH_MAP

이를 전처리 작업하면
typedef enum {
    op_enter,
    op_enter_with_activation,
    op_init_arguments,
    op_create_arguments,
    op_convert_this,
    op_new_object,
    op_new_array,
    op_new_regexp,
    op_mov,
    op_end,
} OpcodeID;


const int numOpcodeIDs = op_end + 1;


const int op_enter_length = 1;
const int op_enter_with_activation_length = 2;
const int op_init_arguments_length = 1;
const int op_create_arguments_length = 1;
const int op_convert_this_length = 2;
const int op_new_object_length = 2;
const int op_new_array_length = 4;
const int op_new_regexp_length = 3;
const int op_mov_length = 3;
const int op_end_length = 2;


const int opcodeLengths[numOpcodeIDs] = { 1, 2, 1, 1, 2, 2, 4, 3, 3, 2, };


이렇게 된다.
깔끔하지 아니한가?
:

[C/C++] Copy constructor, Copy assignment

CS/C/C++ 2009. 9. 10. 11:07
참조 : The C++ Programming Language 3rd Ed.

class X
{
	// ...
	X(Sometype);	// constructor : create objects
	X(const X&);	// copy constructor
	X& operator=(const X&) // copy assignment : cleanup and copy
	~X()	// destructor : cleanup
};


여기서 객체가 대입이 되는데, 객체의 생성 시점에서 대입이 이루어 질 때는, copy constructor가 사용된다.
하지만, 이미 생성되어 있는 객체에 대입이 이루어 질 경우는 copy assignment가 사용된다.
따라서, copy assignment에서는 이미 생성되어 있는 객체를 cleanup 해주고 copy 해야 한다.

즉,
Sample X(10);
Sample Y(20);
Sample Z = X; // copy constructor
Z = Y;        // copy assignment

세 가지 이상의 객체가 복사되는 경우가 있다.
1. 함수의 인자로 전달
2. 함수의 리턴 값
3. 예외 전달

  
#include <iostream>
using namespace std;

class Sample
{
public:
	Sample(int e);
	Sample(const Sample&);
	Sample& operator=(const Sample&);
	~Sample();

private:
	int _elem;
};

Sample::Sample(int e) : _elem(e)
{
	cout << "Constructor : " << this << endl;
}

Sample::Sample(const Sample& s)
{
	cout << "Copy constructor : " << this << endl;

	_elem = s._elem;
}

Sample& Sample::operator=(const Sample& s)
{
	cout << "Copy assignment : " << this << endl;

	_elem = s._elem;
	return *this;
}

Sample::~Sample()
{
	cout << "Destructor : " << this << endl;
}

Sample g(Sample s)
{
	return s;
}

int main(void)
{
	Sample s(1);
	s = g(s);
	return 0;
}


결과는 다음과 같다.

Constructor      : 0x22cc50
Copy constructor : 0x22cc30
Copy constructor : 0x22cc40
Copy assignment  : 0x22cc50
Destructor       : 0x22cc40
Destructor       : 0x22cc30
Destructor       : 0x22cc50



:

[C/C++] const

CS/C/C++ 2009. 9. 10. 09:15
원문 : Effective C++

char greeting[] = "Hello";

char *p = greeting;

const char * p = greeting;        // 상수 데이터 (char const * p = greeting;)
char * const p = greeting;        // 상수 포인터      
const char * const p = greeting;  // 상수 데이터, 상수 포인터



class Sample
{
public:
    Sample(char e) : _elem(e) {}
    const char* Get() const { return &_elem; }
    // 앞의 const는 return type이 const라는 것이고, 뒤의 const는 상수 멤버임을 의미한다.
    // 상수 멤버란, 어떤 멤버 함수가 그 객체의 어떤 데이터 멤버도 건드리지 않아야 함(static 멤버 제외).

private:
    char _elem;
};

만약,
char* Get() const { return &_elem; }
같이 한다면, 상수 객체에 대한 포인터를 리턴받아 값을 수정하는 것이 가능해 지므로 compile error.



const 키워드가 있고 없고의 차이만 있는 멤버 함수는 오버로딩이 가능하다.
class TextBlock
{
public:
    ...
   
// 상수 객체에 대한 operator[]
    const char& operator[](std::size_t position) const { return text[position]; }
    // 비 상수 객체에 대한 operation[]
    char& operator[](std::size_t position) { return text[poistion]; }
private:
    std::string text;
};


TextBlock tb("Hello");       
tb[0] = 'x';    // 비 상수 멤버를 호출


const TextBlock ctb("World");
cout << ctb[0]; // 상수 멤버를 호출

:

[C/C++] Shift 연산자

CS/C/C++ 2009. 9. 6. 01:06
2개의 shift 연산자

a << b : a를 b반큰 왼쪽으로 Shift 시킨다.
a >> b : a를 b만큼 오른쪽으로 Shift 시킨다.

왼쪽으로 이동시킬 때, 오른쪽에는 0이 채워진다.
오른쪽으로 이동 이동시킬 때, MSB에는 a의 부호 비트가 채워진다.

-6이 표현되는 비트는
1111 1111 1111 1111 1111 1111 1111 1010
이 된다.

-6 << 1 한다면, 이는
1111 1111 1111 1111 1111 1111 1111 0100
이 되고, 이는 -12 이다.
왼쪽으로 Shift 시에는 오른쪽에 무조건 0이 채워지기 때문에, 중간에 부호가 바뀌는 경우가 생길 수 있다.


-6 >> 1 한다면, 이는
1111 1111 1111 1111 1111 1111 1111 1101
이 되고, 이는 -3 이다.
음수의 표현을 2의 보수법으로 나타내기 때문에, MSB에 부호비트를 유지 함으로써, Shift시에도 올바른 값이 표현된다.


:

[C++] Class Member Function 의 저장과 호출

CS/C/C++ 2009. 9. 3. 11:10

참조 : Gof Design Pattern

Command 패턴에 나온 예이다

  
#include <iostream>
using namespace std;

class Command
{
public:
	virtual void Execute() = 0;
};

template <class Receiver>
class SimpleCommand : public Command
{
public:
	typedef void (Receiver::*Action) ();

	SimpleCommand(Receiver* r, Action a) : _receiver(r), _action(a) {}
	virtual void Execute();

private:
	Action _action;
	Receiver* _receiver;
};

template<class Receiver>
void SimpleCommand<Receiver>::Execute()
{
	(_receiver->*_action)();
}


class MyClass
{
public:
	MyClass() {}
	MyClass(const MyClass &) {}
	MyClass(const MyClass *) {}
	void MyAction() { cout << "MyClass Action\n"; }
};

int main(void)
{
	MyClass* receiver = new MyClass;
	Command* aCommand = new SimpleCommand<MyClass>(receiver, &MyClass::MyAction);
	aCommand->Execute();
}



형정의
typedef void (Receiver::*Action) ();

전달
Action _action =  &MyClass::MyAction;

호출
(_receiver->*_action)();



후아...


:

[Win32] WM_COMMAND

CS/C/C++ 2009. 9. 1. 23:08
The WM_COMMAND message is sent when the user selects a command item from a menu, when a control sends a notification message to its parent window, or when an accelerator keystroke is translated.

WM_COMMAND가 받는 경우는
1. 사용자가 메뉴에서 command item을 선택했을 때 (메뉴)
2. 컨트롤이 부모 윈도우로 통지 메세지를 보낼 때 (컨트롤)
3. 엑셀레이터키가 해석될 때 이다. (Accelerator)

즉, 메뉴, 컨트롤, 엑셀러레이터 의 3가지의 경우이다.
일단 각각을 살펴보기 전에 MSDN에 있는 WM_COMMAND의 파라미터가 어떻게 해석되는가 하면

Message Source wParam(high word) wParam(low word) lParam
Menu 0 Menu identifier (IDM_*) 0
Accelerator 1 Accelerator identifier (IDM_*) 0
Control Control-defined
notification code
Control identifier Handle to the
control window
  
요렇다.


일단 윈도우 메세지가 처리되는 과정을 보기 위해 Win Main을 보면

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	// ...
	MSG msg;
	// ...
	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTWINDOW));
	// ...
	while (GetMessage(&msg, NULL, 0, 0))	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return (int) msg.wParam;
}

요렇게 되어있다.그럼 다시 GetMessage()는 어디서 msg를 가져오는 것일까...

MSDN에 보면This function retrieves a message from the calling thread's message queue and places it in the specified structure. 라고 되어있다.
즉,쓰레드의 메세지 큐에서 가져오는 것이다.

그런데, 하나의 UI 쓰레드(메세지큐를 가질 수 있는 쓰레드)는 여러 개의 윈도우 프로시저를 가질 수 있는데, 어떤 윈도우 프로시저에 이 메세지를 전달 해야 할까...

GetMessag()는에 MSG구조체를 채워 주는데, 이 구조체가
typedef struct {
    HWND hwnd;   
    UINT message;   
    WPARAM wParam;   
    LPARAM lParam;   
    DWORD time;   
POINT pt;
} MSG, *PMSG;
요렇게 생겨 먹었다.

MSDN에 보면 hwnd는 Handle to the window whose window procedure receives the message. hwnd is NULL when the message is a thread message. 라고 되어 있다.

즉, 이 메세지를 처리할 윈도우 프로시저를 가지고 있는 윈도우의 핸들을 GetMessage()에서 알게 되고, 핸들을 알게 된다면 그 핸들 클래스의 윈도우 프로시저를 알 수 있다. 따라서 DispatchMessage()에서 해당 윈도우를 처리할 등록된 윈도우 프로시저로 디스패치 해 줄수 있게 된다.



1. Control

일단 컨트롤의 경우는, (컨트롤 이라는 의미를 미리 등록된, 즉, RegisterClass에 등록된 클래스 라고 생각 했다) 자신을 생성한 윈도우(부모 윈도우)에 어떤 이벤트가 발생했음을
PostMessage(hParentWindow, WM_COMMAND, MAKEWORD(ID, NOTIFICATION_CODE), handle);
로 알리는 것일까?

그런데!!!
button클래스를 생각해 보면, 모든 버튼은 이 button 클래스로부터 만들어 지게 되는데, 그렇다면 윈도우즈에 있는 모든 button은 button클래스에 등록된 하나의 윈도우 프로시저에서 처리된다는 것일까?
클래스를 구조체를 보면,

typedef struct {
    UINT cbSize;
    UINT style;
    WNDPROC lpfnWndProc;
    int cbClsExtra;
    int cbWndExtra;
    HINSTANCE hInstance;
    HICON hIcon;
    HCURSOR hCursor;
    HBRUSH hbrBackground;
    LPCTSTR lpszMenuName;
    LPCTSTR lpszClassName;
    HICON hIconSm;
} WNDCLASSEX, *PWNDCLASSEX;

즉, 인스턴스와 프로시저가 같이 등록되게 되어있다. 하지만, 인스턴스마다 다른 윈도우 프로시저를 사용한다는 것은 말이 안된다. 같은 일을 하는 윈도우인데 프로시저가 다름 이상하니깐... 그렇다면?

spy로 button클래스로 생성한 버튼의 윈도우 프로시저와 인스턴스핸들 값을 보면... 어떤 인스턴스이던지 프로시저의 값은 같고, 인스턴스 핸들의 값은 항상 0 이다. ... 쏙았다.... 역시 spy가 짱... -_-;

인스턴스 핸들의 값이 0이라는 것은 어떤 전역적인 인스턴스, 혹은 인스턴스와 상관이 없다는 것일 것이고(이것이 운영체제에서 관리되는어떤 것이라고 생각한다.) 이것은 컨트롤이 받는 메시지 자체가 해당 인스턴스의 메세지 큐와는 관련이 없다는 것을 의미하는 것일것이다. 이렇게 커널에서 관리되는 메세지큐와 프로시저라면, 굳이 Notification을 보내기 위해 PostMessage()api를 사용할 필요는 없을 것이다. 해당 UI 쓰레드의 메세지큐에 집어 넣어 놓으면 펌핑 해 갈테니...(api로 집어 넣었을 수도 있지만, 어차피 운영체제에서 관리 된다면 api가 아닌 좀더 빠른 무언가로 큐에 집어 넣어 놓지 않을까...)

결론을 얘기하면.
1. 버튼이 눌린다.
2. 이 눌림 메세지 자체는 인스턴스와 상관없이 커널단의 메세지 큐에서 관리될 것이다.
3. 해당 메세지 큐에서 메세지가 등록된 윈도우에 해당하는 윈도우 프로시저에 의해 처리된다.
4. 그 컨트롤의 부모 윈도우(hwndParent)가 속한 UI 쓰레드의 메세지 큐에 WM_COMMAND 메세지를 넣어 놓는다.
5. 이제 hwndParent의 UI 쓰레드에서 메세지를 펌핑한다.
6. DispatchMessage()에서 hwndParent가 등록되어 있는 WNDPROC로 이 메세지를 Dispatch한다.
7. 해당 WNDPROC에서 WM_COMMAND를 받는다.

아마도. -_-;

그렇다면, 사용자가 컨트롤을 흉내내는 경우라면,
윈도우 클래스를 등록하고, 이 클래스로 윈도우를 만들고, 클래스에 등록된 윈도우 프로시저에서 2-4의 과정에 해당하는 과정을 해 주면 될 것이다.
만약 버튼의 클릭 되었음을 알린다면, 해당 윈도우 프로시저의 WM_LBUTTONUP 메세지에서
PostMessage(hParentWindow, WM_COMMAND, MAKEWORD(ID, NOTIFICATION_CODE), handle);
해 주면 될 것이다.



2. Menu, Accelerator

Menu는 WM_COMMAND가 전달 되는 것은, 마우스로 메뉴의 아이템을 클릭 했을 때 이고,
Aeccelerator는 WinMain에서 TranslateAccelerator(msg.hwnd, hAccelTable, &msg) 된 정보 이다.

일반적으로 ALT+F(Nmemonic)로 메뉴 자체가 선택되는 것은 이와는 다른 메커니즘인 듯 하다. 나중에 시간 나면 알아봐야지...


:

[C/C++] _strdup

CS/C/C++ 2009. 8. 14. 00:27
참조 : MSDN

char *_strdup(const char *strSource);
wchar_t *_wcsdup(const wchar_t *strSource);
unsigned char *_mbsdup(const unsigned char *strSource);

Return Value
Each of these functions returns a pointer to the storage location for the copied string or NULL if storage cannot be allocated.

Remarks
The _strdup function calls malloc to allocate storage space for a copy of strSource and then copies strSource to the allocated space.
Because _strdup calls malloc to allocate storage space for the copy of strSource, it is good practice always to release this memory by calling the free routine on the pointer returned by the call to _strdup.
:

[MFC/C++] GetSafeHwnd()

CS/C/C++ 2009. 8. 3. 15:25
참조 : MFC source code

_AFXWIN_INLINE HWND CWnd::GetSafeHwnd() const
	{ return this == NULL ? NULL : m_hWnd; }

별 생각없이 GetSafeHwnd()를 사용하곤 했는데, 소스보니 저리 되있다.
부모 윈도우를 추적하는등의 순환문에서 사용할 경우 따로 NULL인지 판별 해 주지 않아도 되고,
Runtime error를 방지(?) 할 수 있다.
NULL이 아닌것이 확실한 경우 굳이 GetSafeHwnd()를 쓸 이유는 없을듯...
:

[C++] 내부 클래스에서 외부 클래스의 Function에 접근

CS/C/C++ 2009. 7. 30. 11:22
내부 클래스를 포함하고 있는 외부 클래스에서 정의된 함수가 가상 함수인 경우,

내부 클래스의 함수에서 외부 클래스의 주소를 정확히 계산 하지 않으면 가상 함수 테이블을 찾을 수 없기 때문에 해당 함수를 호출 할 수 없게 되어 Runtime error가 발생한다

(가상 함수가 아닌 경우는 VTBL을 찾을 필요가 없기 때문에 굳이 시작 주소를 찾지 않고 캐스팅 만으로 충분)

참고 : MFC source code
#define offset(s, m) \
(size_t)&reinterpret_cast<const volatile char&>((((s *)0)->m));

class A
{
public:
	class X
	{
	public:
		void callAVtFunc();
	} m_x;

	virtual void VtFunc() { std::cout << "OK\n"; }
};

void A::X::callAVtFunc()
{
	A* a = ((A*)((char*)this - offsetof(A, m_x)));
	a->VtFunc();
}

int main(void)
{
	A a;
	a.m_x.callAVtFunc();

	return 0;
}
:

[C++] Static member initialization

CS/C/C++ 2009. 4. 7. 11:24
Q.
// Widget.cpp
int Widget::state_;
위와 같은 코드를 보시고 class의 static member 변수의 초기화를 안했다고 생각하고 있진 않으신가요?.
표준 C++에서 정의하고 있는 static member 변수 초기화에 대해 간단히 정리했습니다.



A.
먼저 표준 C++에서 정의하고 있는 세가지 storage duration에 대해 간단히 정리해보겠습니다.

static storage duration - dynamic storage duration을 가지지 않으면서 local인 객체들은 모두 static storage duration을 가지게 됩니다. 이 storage에 있는 객체들은 속해 있는 프로그램의 duration만큼 지속됩니다. 또한 local 변수의 선언에 static keyword를 사용하게 되면 역시 static storage duration을 가지게 됩니다. class의 data member에 사용된 static keyword도 마찬가지입니다.
 
automatic storage duration - auto, register를 명시적으로 선언한 local 객체, 혹은 static, extern등이 명시적으로 선언되지 않은 local 객체들은 automatic storage duration을 가지게 됩니다. 이 storage에 있는 객체들은 자신이 생성된 블록이 끝나기 전까지만 지속됩니다.
 
dynamic storage duration - 프로그램 수행 중에 new-expressions을 가지고 생성된 객체들은 dynamic storage duration을 가지게 되며 delete-expressions를 사용하여 파괴될 수 있습니다.
 
위와 같은 용어의 이해를 바탕으로 ISO/IEC-14882의 3.6.2(1)을 참고하면 다음과 같습니다.

Static storage duration을 가지는 객체들을 위한 storage는 어떤 다른 초기화보다 먼저 0으로 초기화된다(zero-initialization).
이러한 초기화와 상수 초기화를 합쳐서 정적(static) 초기화라고 부르고 나머지는 동적(dynamic) 초기화라고 부른다.
 
static storage duration을 가지는 POD(Plain Old Data) 객체들의 상수 초기화는 항상 어떤 다른 dynamic 초기화보다 먼저 일어나게 된다.
 
동적 초기화되는 객체들과, 같은 translation unit안의 namespace scope에 정의된 static storage duration을 갖는 객체들은 transation unit안에 선언된 순서에 따라 초기화된다.
 
// Widget.cpp
int Widget::state_;
이제 state_ 변수는 static storage duration을 가지게 되고 따라서 다른 종류의 초기화에 앞서 0으로 초기화된다는 사실을 알 수 있습니다.

따라서 위의 코드는 초기화를 잊은 코드가 아니라는 사실을 알 수 있습니다.
단지 코드의 작성자는 그 state_ 변수를 0으로 초기화하려고 했었던 것이죠.

참고로 local에 선언된 static 변수는 어떤 다른 초기화 과정에 앞서 0으로 초기화됩니다.
만약 그 변수가 constant-expressions를 가진 POD 타입일 경우 선언되어 있는 블록이 시작되기 전에 초기화되며 이외의 경우 선언된 라인이 처음 실행되는 순간에 초기화됩니다. 이때 객체의 생성자가 exception을 throw하게 되면 다음 실행되는 순간에 다시 초기화를 시도하게 됩니다.

만약 이 객체가 생성되는 순간에 다시 함수에 재진입(re-enter)하게 되면 (recursively) 결과는 정의되어 있지 않습니다(undefined). 아래의 코드를 참고하세요.

int foo(int i) {
static int s = foo(2 * i); // recursive call. undefined
return i + 1;
}
 
Static storage duration을 가지는 변수들이 하나의 translation unit 안에 정의되어 있다면 선언되어 있는 순서대로 초기화된다는 것을 보장받지만 다른 translation unit 안에 정의되어 있는 static storage duration을 가지는 변수들간의 초기화 순서는 정의되어 있지 않습니다. 따라서 이러한 다른 translation unit의 변수들간의 dependency는 가능하면 피해야 합니다.

하지만 어떠한 경우라도 변수들의 파괴는 정확히 초기화 순서의 반대로 일어납니다.

이 글은 ISO/IEC 14882 문서를 참고하여 만들어졌습니다.

이 페이지의 내용보다 더 자세한 객체의 생성, 삭제에 관련된 다양한 사항들은 위의 문서를 참고하시면 됩니다.




정적 클래스 멤버는 객체의 일부가 아니라 따로 저장된다. 
정적 클래스 멤버에 대해서는 정적 멤버를 클래스 선언 밖에서 별도의 명령문으로 따로 초기화 한다.
하지만, 정적 멤버가 정수형 또는 열거형의 상수이면 클래스 선언 자체에서 초기화할 수 있다.
:

[C++] 상속

CS/C/C++ 2009. 2. 28. 04:23

  public 상속 protected 상속  private 상속 
 public 멤버 public  protected private
 protected 멤버 protected protected  private 
 private 멤버 접근 불가 접근 불가  접근 불가 

:

[C++] casting

CS/C/C++ 2009. 1. 19. 08:09
[ static_cast ] 
static_cast는 암시적으로 수행될 수 있는(역변환을 포함하여) 캐스팅을 수행할 수 있도록 한다.
 
double d = 3.14159265;
int i = static_cast<int>(d);
클래스에 대한 포인터 관점에서 static_cast는 상속된 클래스에서 기초 클래스로(암시적으로 수행되는 vaild conversion) 혹은 그 반대(기초 클래스에서 상속된 클래스)로의 캐스팅을 해 준다.
  
class Base {};
class Derived : public Base {};

Base *a = new Base;
Derived *b = static_cast<Derived *>(a);


[ dynamic_cast ] 
체크는 런타임시에 수행되며, 만약 변환된 포인터가 요청된 type의 유효한 객체에 대한 포인터가 아니라면 NULL 포인터를 리턴한다. (참조자였다면 bad_cast 예외를 던진다.) 

(다운 캐스팅 예)
class Base { virtual dummy() {} };
class Derived : public Base {};

Base* b1 = new Derived;
Base* b2 = new Base;

Derived* d1 = dynamic_cast<Derived *>(b1); // succeeds
Derived* d2 = dynamic_cast<Derived *>(b2); // fails: returns 'NULL'
(크로스 캐스팅 예)
class BaseOne { virtual dummy() {} };
class BaseTwo { virtual dummy() {} };
class Derived : public BaseOne, public BaseTwo
{
void dummy() {}
};

BaseOne* pBaseOne = NULL;
BaseTwo* pBaseTwo = new Derived;

pBaseOne = pBaseTwo; // error : 타입 변환을 할 수 없다.
pBaseOne = dynamic_cast<BaseOne*>( pBaseTwo ); // success


[ reinterpret_cast ] 
서로 관계가 없는 type간의 변환을 수행한다.
class A {};
class B {};

A * a = new A;
B * b = reinterpret_cast<B *>(a);


[ const_cast ] 
포인터 혹은 참조형의 상수성을 제거하는데 사용
class C {};

const C *a = new C;
C *b = const_cast<C *>(a);


[참조]
http://www.codeguru.com/forum/showthread.php?t=312456 
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tutorial&no=146
:

[C++] 연산자 우선순위

CS/C/C++ 2009. 1. 18. 22:27

::

Scope resolution

None

.

Member selection (object)

->

Member selection (pointer)

[]

Array subscript

()

Function call

()

Member initialization

++

Postfix increment

--

Postfix decrement

typeid()

Type name

cast

Type cast (conversion)

sizeof

Size of object or type

++

prefix increment

--

postfix decrement

~

One's complement

!

Logical not

-

Unary minus

+

Unary plus

&

Address of

*

Indirection

new

Create object

delete

Destroy object

()

Cast

.*

Pointer to member (objects)

->*

Pointer to member (pointer)

*

Multiplication

/

Division

%

Modulus

+

Addition

-

Subtraction

<<

Left shift

>>

Right shift

<

Less than

>

Greater than

<=

Less than or equal to

>=

Greater than or equal to

==

Equality

!=

Inequality

&

Bitwise AND

^

Bitwise exclusive OR

|

Bitwise inclusive OR

&&

Logical AND

||

Logical OR

E1 ? E2 : E3

Conditional

=

Assignment

*=

Multiple assignment

/=

Division assignment

%=

Modulus assignment

+=

Addition assignment

-=

Subtraction assignment

<<=

Left-shift assignment

>>=

Right-shift assignment

&=

Bitwise AND assignment

|=

Bitwise inclusive OR assignment

^=

Bitwise exclusive OR assignment

throw expr

Throw expression

,

comma




:

[C/C++] Pointers

CS/C/C++ 2009. 1. 18. 20:28
1. 배열의 끝을 하나 넘어선 포인터
배열의 끝을 하나 지난 포인터를 취하는것은 동작하는 것이 보장된다.
이것은 많은 알고리즘에서 중요하다.
하지만, 이런 포인터는 배열의 요소를 실제로 가리키고 있지 않기때문에, 읽거나 쓰는데 사용되선 안된다.
int main(void)
{
	...
	char a[3] = {'a', 'b', 'c'}

	char *start = &a[0];
	char *end = &a[4];

	while (p != end) cout << *p++;
	...
	return 0;
}

2. 포인터 연산 
하나의 포인터에서 다른 포인터를 뺐을 경우, 결과값은 포인터 값이다.
이때 포인터 연산은 같은 배열에 대해서 이루어 져아 한다.
 
void f()
{
	int v1[10];
	int v2[10];

	int i1 = &v1[5] - &v1[3]; // i1 = 2
	int i2 = &v1[5] - &v2[3]; // result undefined

	int *p1 = v2 + 2; // p1 = &v2[2]
	int *p2 = v2 - 2; // result undefined
	int *p3 = &v2[4] - 2; // p3 = &v2[2]
}

3. Pointer to constant VS Constant pointer
  
int main(void)
{
void f()
{
	char s[] = "Grom";
	
	const char* pc = s; // pointer to constant. *PC가 상수
	char* const cp = s; // constant pointer. CP가 상수
	const char* const cpc = s; // constant pointer to constant. *CPC, CPC 모두 상수
}
포인터를 상수로 만드는 선언자는 *const 이며, const* 선언자는 없다.
따라서 *전에 나오는 const는 기본 타입으로 간주된다.
 
char *const cp; // const pointer to char
const char* pc; // pointer to const char
char const* pc; // pointer to const char
원문 : C++ Programming Laguage 3rd Edtion.
:

[C++] Enumerations

CS/C/C++ 2009. 1. 18. 19:02
기본적으로, 열거자는 0부터 값을 증가 시킨다.
열거자는 이름을 가질 수 있으며, 각 열거자는 다른 type을 가지게 된다.
enum keyword {ASM, AUTO, BREAK};
위에서 AUTO는 keyword type이다.
  
void f(keyword key)
{
	switch (key) {
	case ASM:
		// do something
		break;
	case BREAK:
		// do something
		break;
	}
}
열거자는 정수형 타입의 constant-expression에 의해 초기화될 수 있다.
열거자의 범위는 반올림 해서 2의 지수승에 가장 가까운 수 -1 을 갖는다.
enum e1 {dark, light}; // range 0:1
enum e2 {a = 3, b = 9}; // range 0:15
enum e3 {min=-10, max=1000000} // range -1048575:1048575

정수형 값은 명시적으로 열거자 형으로 변환될 수 있다.
변환이 열거자 값의 변환 범위에 없다면, 결과는 비확정적인다.

원문 : C++ Programming Laguage 3rd Edtion.
:

[C++] Misc.

CS/C/C++ 2009. 1. 18. 17:50
Size
1 ≡ sizeof(char) ≤ sizeof(short) ≤ sizeof(int) ≤sizeof(long)
1 ≤ sizeof(bool) ≤ sizeof(long)
sizeof(char) ≤ sizeof(wchar_t) ≤ sizeof(long)
sizeof(float) ≤ sizeof(double) ≤ sizeof(long double)
sizeof(N) ≡ sizeof(signed N) ≡ sizeof(unsigned N)

cf) limit 확인
  
#include <limits>
// ...
numeric_limits<float>::max();
// ...

Declator
* pointer  prefix
*const constant pointer  prefix 
reference  prefix 
[] array  postfix 
()  function  postfix 
postfix 선언자는 prefix 보다 더 강하게 결합한다. *kings[]는 포인터의 벡터.


전역 변수 접근
지역 변수는 접근할 수 없지만, 숨겨진 전역 변수는 다음과 같이 접근 가능하다.
  
int x;

void f2()
{
	int x = 1; // hide global x
	::x = 2; // assign to global x
	x = 2; // assign to local x
	// ...
}

초기화
초기화값이 지정되지 않은 global, namespace, local static은 적당한 타입의 0으로 초기화된다.


wide character prefix
L"angst"와 같이 L prefix는 wide character를 나타낸다.


constant variable
const 키워드는 객체를 상수로 선언하기 위해 객체의 선언에 추가될 수 있다.
const int x = 10;
extern const int x;
를 헤더파일에 선언할 수 있음. (const 가 아닌경우 중복 정의)


pointing constant pointer
constant가 아닌 pointer로 constant인 pointer를 pointing할 수 없다.

 
void f()
{
	int a = 1;
	const int c = 2;
	const int* p1 = &c; 	// ok
	const int* p2 = &a; 	// ok
	int* p3 = &c; 		// error
}

참조형 초기화
일반 T&의 초기값 T형의 lvalue여야 하지만, 
const T&의 초기값은 다음과 같은 경우에 T형의 lvalue를 필요로 하지 않는다.
[1] 묵시적으로 T형으로의 형변환이 일어난 후
[2] T 형의 임시 변수에 결과값이 대입되고
[3] 임시 변수가 초기값으로 사용된다.

double& dr = 1; // error : lvalue needed
const double& cdr = 1; // ok

두번째 초기화는 다음과 같은 해석이 일어날 것이다.
double temp = double(1);
const double& cdr = temp;

임시로 생성된 값은 참조 범위가 끝날때까지 영속한다.


형변환
  
void f()
{
	void* pv = pi; 	// ok: implicit conversion of int* to void*
	*pv; 			// error : can't dereference void*
	pv++; 		// error : cna't increment void*
	
	int* pv2 = static_cast<int*>(pv); 		// explicit conversion back to int*
	
	double* pd1 = pv; 					// error
	double* pd2 = pi; 					// error
	double* pd3 = static_cast<double*>(pv); 	// unsafe
}
다른 type의 객체를 가리키는 포인터를 "cast"하는 것은 안전하지 못하다.
int형을 double로 cast 하는 경우, 일반적으로 int형은 4바이트 경계, double형은 8바이트 경계를 갖기 때문에 잘못된 결과를 가지게 된다.


구조체 맴버에서의 구조체 이름 사용
구조체의 type은 선언한 후 바로 사용 가능하지만, 새로운 객체의 생성은 그 구조체의 선언이 완전히 끝난 후에야 가능하다.

  
struct Link {
	Link* prev;	// ok
	Link* next;	// ok
	Link member;	// error: recursive definition
}
:

[C++] Virtual Function

CS/C/C++ 2009. 1. 18. 16:14
 
class Stack {
public:
	class Underflow{};
	class Overflow{};

	 // =0은 상속받은 클래스는 이 함수들을 다시 정의해야함을 의미
	virtual void push(char c) = 0;
	virtual void pop() = 0;
}

class Array_stack : public Stack {
	char* p;
	int max_size;
	int top;
public:
	Array_stack(int s);
	~Array_stack();

	void push(char c);
	char pop();
};

class List_stack : public Stack {
	list<char> lc;
public:
	List_stack() {}
	void push(char c) { lc.push_front(c); }
	char pop();
}

char List_stack::pop()
{
	char x = lc.front();
	lc.pop_front();

	return x;
}



void f(Stack& s_ref)
{
	s_ref.push('c');
	if (s_ref.pop() != 'c') throw Bad_pop();
}

void g()
{
	Array_stack as(200);
	f(as);

void h()
{
	List_stack ls;
	f(ls);
}

h()에서 f()가 호출되어졌을 때, List_stack::pop()이 호출되어져야만 한다.
g()에서 f()가 호출되어졌을 때, Array_stack::pop()이 호출되어져야만 한다.
이것을 풀기위해, Stack 객체는 런타임에 호출되어질 수 있는 함수를 가리키는 정보를 가지고 있어야만 한다.
이것을 위한 일반적인 구현 방법은 컴파일러가 virtual function 이름을 function을 가리키는 포인터들의 테이블의 index로 만드는 것이다. 이 테이블은 "a virtual function table" 혹은 간단하게 vtbl이라고 불린다.
virtual functino을 가지고 있는 각 클래스는 자신의 virtual function을 가리킬수 있도록 자신의 vtbl을 가지고 있다.



원문 : C++ Programming Laguage 3rd Edtion.
:

[C++] Representation & Class definition

CS/C/C++ 2009. 1. 18. 14:20
1. Representation
[a] 분리된 idea로써 "it"을 생각할 수 있다면, 그것을 class로 만들어라
[b] 분리된 entity로써 "it"을 생각할 수 있다면, 그것을 어떤 클래스의 object로 만들어라
[c] 두 개의 클래스가 공통 인터페이스를 가지고 있다면, 그 인터페이스를 추상 클래스(abstract class)로 만들어라
[d] 두개의 클래스의 구현이 현저히 의미있는 공통성을 가지고 있다면, 공통된 부분을 기초 클래스(base class)로 만들어라
[e] 어떤 클래스가 객체의 컨테이너라면, 그것을 템플릿(template)로 만들어라
[f] 만약 함수가 컨테이너를 위한 알고리즘을 구현한다면, 그것을 컨네이너 패밀리의 알고리즘을 구현하는 템플릿 함수로 만들어라.
[g] 만약 클래스셋, 템플릿등이 논리적으로 연관되어 있다면 그것들을 common namespace에 위치시켜라.

2. Class definition
[a] 전역 데이타를 사용하지 말아라(member를 사용)
[b] 전역 함수를 사용하지 말아라
[c] public 데이터 멤버를 사용하지 말아라
[d] [a]나 [c]를 피하기 위해 friends를 사용하지 말아라
[e] 클래스에 "type filed"를 놓지 말아라, virtual function을 사용하라
[f] 중요한 최적화를 위해서를 제외하고는 inline 함수를 사용하지 말아라.

원문 : C++ Programming Laguage 3rd Edtion.
:

[C++] C 프로그래머에게의 제안

CS/C/C++ 2009. 1. 18. 13:45
[1] C++ 에서 매크로는 거의 필요하지 않다.
const, enum : 상수를 정의
inline : 함수 호출 오버헤드 줄임
template : 함수와 타입의 군을 정의
namespace : 이름 충돌을 회피
하기 위해 사용할 수 있다.

[2] malloc()을 사용하지 말것
new 는 같은 작업을 더 잘 한다. realloc()대신 vector()를 사용하라

[3] void* 를 피하라
대부분의 경우에, cast는 디자인 에러를 불러온다. 만약 명시적인 형 변환이 필요하다면 "new casts"중 하나를 사용하라.

[4] C 스타일의 문자열의 사용을 최소화 하라
C++의 표준 라이브러리 string과 vector클래스는 전통적인 C스타일에 비해 간단한 프로그래밍을 제공할 수 있다.

[5] NULL 대신 0을 사용하라
어떤 오브젝트도 0의 주소로 할당되지는 않는다. 
C++에서는 type 확인이 더 엄격하기 때문에 NULL 매크로보다는 plain 0를 사용해라. 이것이 더 적은 문제를 일으킨다.
정 NULL을 사용하고 싶다면, const in NULL = 0 을 사용하라. 

원문 : C++ Programming Laguage 3rd Edtion.
: