<

C++/C Language - Tips

>
Home | Tips | Reference

Revision은 이미 작성된 글들에 대한 추가/삭제/수정과 같은 작업이 발생한 경우이며 case study는 작성된 글과 관련된 실제 사례에 대한 내용이 추가된 경우를 나타냅니다. 작업한 부분의 검색을 돕기 위하여 각각 다른 색을 사용했습니다.

페이지의 하단에 있는 양식을 통해 메일링 리스트에 가입할 수 있습니다.

아래 글들은 쓰여진 시간을 기준으로 정렬되었습니다.


2002.11

 

std::count

iwongu.11.25.

template <class In, class T>
typename iterator_traits<In>::difference_type count(In first, In last, const T& val);

template <class In, class Pred>
typename iterator_traits<In>::difference_type count_if(In first, In last, Pred p);

위의 함수는 algorithm에 정의되어 있는 count와 count_if 알고리즘입니다.
주어진 iterator 사이에서 정해진 값이나 조건에 맞는 element의 갯수를 리턴하는 함수인데 어째서 return type으로 difference_type 이 사용되었을까요?



2002.09

 

Self documenting

iwongu.09.30.

void f() {
	TextHandler t;
	t.sendText("Hello, world", true);
}

class TextHandler {
public:
	void sendText(const std::string& msg, bool sendNewLine);
};

위의 코드에 사용된 boolean 타입에는 어떤 문제가 있을까요? C/C++ Users Journal에 실렸던 Self documenting과 관련된 내용을 소개합니다.



2002.06

 

Double-Checked Locking

iwongu.06.12.

Singleton& Singleton::Instance() {
	if (!pInstance_) {
		pInstance_ = new Singleton;
	}
	return *pInstance_;
}

위의 코드는 Singleton 클래스 구현 중 Instance() 부분입니다. 하지만 위의 코드는 multi-thread 환경에서 사용될 경우 race condition이 발생할 수 있습니다.
Race condition을 방지하기 위해서는 어떤 방법을 사용해야 할까요?



2002.05

 

OCP

iwongu.05.27.

enum ShapeType { circle, square };
struct Shape {
	ShapeType itsType;
};
struct Circle {
	ShapeType itsType;
	// ...
};
struct Square {
	ShapeType itsType;
	// ...
};
void DrawAllShapes(Shape* list[], int n) {
	for (int i = 0; i < n; ++i) {
		Shape* s = list[i];
		switch (s->itsType) {
		case square:
			DrawSquare(static_cast<Square*>(s));
			break;
		case circle:
			DrawCircle(static_cast<Circle*>(s));
			break;
		}
	}
}

위의 코드에 있는 DrawAllShapes 함수의 경우 새로운 Shape가 추가될 때마다 변경되어야 합니다.
이번 글에서는 이러한 변경과 관련하여 지켜야 할 원칙 중 하나인 OCP(Open-Closed Principle)에 대해서 알아봅니다.



Volatile

iwongu.05.07.

class Gadget {
public:
	void wait() {
		while (!flag_) {
			Sleep(1000);
		}
	}
	void wakeup() {
		flag_ = true;
	}
private:
	bool flag_;
};

위의 클래스는 multi-thread 프로그램에서 사용되기 위해 작성된 코드입니다.
잘못된 부분을 찾아서 수정해보세요.



2002.04

 

Revision.04.23

ScopeGuard - exception_spec



Traits

iwongu.04.20.

void FetchIntField(db_cursor& cr, unsigned int col, int& val) {
	if (cr.column_type[col] != DB_INTEGER)
		throw std::runtime_error("Column type mismatch");
	
	if (!db_access_column(&cr, col))
		throw std::runtime_error("Cannot transfer data");
	
	db_integer temp;
	memcpy(&temp, cr.column_data[col], sizeof(temp));
		
	db_release_column(&cr, col);	// Required by the DB API for cleanup
		
	val = static_cast<int>(temp);	// Convert from the database native type to int
}

위의 코드는 (가상의) relational DB에서 cursor가 위치한 record의 특정 column에 있는 int 타입의 값을 가져오기 위해 사용될 수 있는 helper function입니다.
위의 함수를 generic하게 작성하려면 어떤 방법을 사용해야 할까요?



Revision.04.17

ScopeGuard - andrei



Case study.04.14

Pimpl idiom - headers



using directive

iwongu.04.14.

// Widget.h
#include <map>
#include <string>
using namespace std;

class Widget {
public:
	// ctor/dtor/member functions...
private:
	typedef map<string, Widget*> WidgetTable;
	WidgetTable table_;
};

위의 코드의 using directive에는 어떤 문제가 있을까요?
using directive의 사용법에 대해 정리했습니다.



Revision.04.12

Static member initialization - trans_unit



Case study.04.10

ScopeGuard - session_guard



ScopeGuard

iwongu.04.08.

session_guard.04.10

andrei.04.17

exception_spec.04.23

void other_func();	// maybe, throw exception

class Widget {
public:
	bool doSomething() {
		mutex_.lock();			// don't forget to call Mutex::unlock();
		int file = open_file("temp.temp");	// don't forget to call close_file(int );
				
		if (...) return false;		
		other_func();
	
		close_file(file);
		mutex_.unlock();		
		return true;
	}	
private:
	Mutex mutex_;	
};

Resource management에 관련된 함수 혹은 멤버 함수들은 open-close, create-destroy, lock-unlock, enter-leave등과 같이 pair로 정의되는 경우가 많이 있습니다. 대부분의 경우 첫번째 함수를 사용하여 object의 사용 권한을 획득한 후 사용이 끝나면 두번째 함수를 호출하여 자원을 반납해야 합니다.
하지만 이러한 작업 역시 생각만큼 쉽지는 않죠.
Exception이 발생하는 경우에도 안전하게 자원을 해제할 수 있는 방법에 대해 정리했습니다.



Revision.04.08

std::auto_ptr - typed_buffers



Bit string

iwongu.04.05.

void check_flag(unsigned long flags) {
	const size_t CHAR_BIT = 8;
	for (int i = 0; i < sizeof(unsigned long) * CHAR_BIT; ++i) {
		if (flags & (1 << i)) cout << i << " bit is set.\n";
	}
}

많은 코드들이 메모리의 크기를 줄이기 위해서 혹은 flag 검사 속도를 개선하기 위해서 위와 같은 비트 연산을 사용하고 있습니다.
하지만 필요한 flag가 32개를 초과할 경우에는 어떤 방법을 사용해야 할까요? (unsigned long 형이 32bit인 경우입니다.)



2002.03

 

Name hiding

iwongu.03.25.

class Base {
public:
	virtual void doSomething();
	virtual void doSomething(int, int);
};

class Derived : public Base {
public:
	virtual void doSomething();
};

int main() {
	Derived d;
	d.doSomething();
	d.doSomething(0, 0);
}

각각의 doSomething() 함수 호출은 어떤 함수를 호출하게 될까요?
Inheritance와 name lookup, 그리고 using declaration에 대해 정리했습니다.



Revision.03.24

NVI (Non-Virtual Interface Idiom) - link



Inheritance

iwongu.03.24.

class Rectangle { /* ... */ }
class Square : public Rectangle { /* ... */ }

Class 구조를 설계하다보면 class들간의 관계를 어떻게 정의해야 할지 결정하기가 어려운 경우가 많이 있습니다.
과연 위의 코드처럼 square는 (IS-A) rectangle일까요?
Inheritance에 관한 몇가지 사항들을 정리했습니다.



Exception safety
part 1

iwongu.03.21.

template <typename T>
class Stack {
public:
	Stack();
	Stack(const Stack&);
	~Stack();
	Stack& operator=(const Stack&);
	size_t size() const;
	void push(const T&);
	T pop();	// if empty, throws exception
private:	
	T* v_;
	size_t vsize_;
	size_t vused_;	
};

위의 Stack 객체는 누구나 한번쯤 구현해 봤을 코드입니다. Exception safety를 고려한다면 어떻게 구현해야 할까요?
이번 part에서는 exception safety를 고려했을때 생각해봐야 할 문제들에 대해 정리했습니다.



Revision.03.14

Pimpl idiom - auto_ptr



std::auto_ptr

iwongu.03.12.

typed_buffers.04.08

class Widget;
void other_func();	// maybe, throw exception
int some_func() {
	Widget* w(new Widget);
	if (...) {
		delete w;
		return -1;
	}
	other_function();
	delete w;
	return 0;
}

new를 사용하여 생성한 객체의 경우 memory leak을 막기 위해서는 사용이 끝난 후 항상 delete를 사용하여 memory를 반환해야 합니다. 하지만 이러한 작업이 항상 말만큼 쉽지는 않죠.
이러한 resource 관리에 도움이 될 수 있는 std::auto_ptr에 대해 정리했습니다.



Pimpl idiom

iwongu.03.10.

auto_ptr.03.14

headers.04.14

class Widget {
public:
	// ... functions
protected:
	// ... functions
private:
	class WidgetImpl* pimpl_;
};

기존의 코드를 보시면서 pimpl_이라고 이름 붙여진 private pointer 변수를 보신적이 있으신가요?
Compilation firewall이라고도 불리는 Pimpl idiom에 대해 정리했습니다.



Cast to reference


iwongu.03.08.

class Widget;
Widget getWidget();
void useWidge(Widge& w);

int somefunc() {

	const Widget& w1 = getWidget();
	Widget& w2 = const_cast<Widget&>(static_cast<const Widget&>(getWidget()));
	
	useWidget(w1);
	useWidget(w2);
}

위의 somfunc 함수에서는 temporary 객체에 대한 reference 변수들을 사용하고 있습니다.
위의 코드는 문제가 없는 코드일까요?



Function declaration


iwongu.03.04.

ifstream dataFile("ints.dat");
list<int> data(istream_iterator<int>(dataFile), istream_iterator<int>());

위의 코드는 ints.dat라는 파일에서 integer들을 읽어 data라는 list에 넣기 위해 작성된 코드입니다.
과연 원하는 결과를 얻을 수 있을까요?



Main function


iwongu.03.03.

int main() { /* ... */ }

main() { /* ... */ }

void main() { /* ... */ }

int main(int argc, char* argv[]) { /* ... */ }

위의 main 함수 선언 중 표준 C++에서 정의하고 있는 main 함수의 선언에는 어떤 것들이 있을까요?
표준 C++에서의 main에 관련된 몇가지 얘기들을 정리했습니다.



Static member initialization


iwongu.03.03.

trans_unit.04.12

// Widget.cpp
int Widget::state_;

위와 같은 코드를 보시고 class의 static member 변수의 초기화를 안했다고 생각하고 있진 않으신가요?.
표준 C++에서 정의하고 있는 static member 변수 초기화에 대해 간단히 정리했습니다.



NVI
(Non-Virtual Interface Idiom)


iwongu.03.03.

link.03.24

class Widget {
public:
	virtual int Process(Gadget&);
	virtual bool IsDone();
	// ...
};

누군가 base class로 사용하기 위해 위와 같은 코드를 작성했다면 과연 어떤 문제가 있을까요?
Template Method 패턴에 대한 이해가 있다면 도움이 됩니다.



Koenig lookup


iwongu.03.02.

namespace A {
	struct X;
	struct Y;
	void f(int);
	void g(X);
}

namespace B {
	void f(int i) {
		f(i);	// which f()?
	}
	void g(A::X x) {
		g(x);	// which g()?
	}
	void h(A::Y y) {
		h(y);	// which h()?
	}
}

Namespace B에 있는 함수들에서 호출된 f(), g(), h()는 각각 어느 함수들을 호출하게 될까요?
C++의 name lookup 규칙에 관한 이해가 필요합니다.



Duff's device


iwongu.03.01.

template <typename T>
void fill_array(T* begin, T* end, const T& data) {

	while (begin != end) {
		
		*begin = data;
		++begin;
	}
}

위의 코드와 같은 단순 루프를 더욱 최적화하려면 어떻게 해야 할까요?
switch와 case문의 동작 원리에 대한 이해가 필요합니다.




메일링 리스트 가입하기:

cpp-tips-subscribe@yahoogroups.com

메일링 리스트 탈퇴하기:

cpp-tips-unsubscribe@yahoogroups.com

그룹에 메일 보내기:

cpp-tips@yahoogroups.com

그룹에 웹-메일 보내기:

http://groups.yahoo.com/group/cpp-tips/post

저장된 메일 보기:

http://groups.yahoo.com/group/cpp-tips

 
본 메일링 리스트는 새로운 글을 알리기 위해서 사용되며 C++/C 언어에 대한 멤버들간의 간단한 질문/답변용으로도 사용될 수 있습니다.
메일링 리스트를 통해 메일을 주고 받는 것 이외의 메일링 리스트 기능(Yahoo! Group)을 사용하시려면 Yahoo! 아이디가 있어야 합니다.
메시지의 처리에는 몇분에서 몇시간까지 소요될 수 있습니다.


2002.9.30. 잘못된 부분에 대해서는 에게 메일 부탁드립니다.