| < |
C++/C Language - Tips |
> |
| Home | Tips | Reference |
Revision은 이미 작성된 글들에 대한 추가/삭제/수정과 같은 작업이 발생한 경우이며 case study는 작성된 글과 관련된 실제 사례에 대한 내용이 추가된 경우를 나타냅니다. 작업한 부분의 검색을 돕기 위하여 각각 다른 색을 사용했습니다.
페이지의 하단에 있는 양식을 통해 메일링 리스트에 가입할 수 있습니다.
아래 글들은 쓰여진 시간을 기준으로 정렬되었습니다.
|
2002.11 |
|
|
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 알고리즘입니다. |
|
2002.09 |
|
|
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 |
|
|
iwongu.06.12. |
Singleton& Singleton::Instance() {
if (!pInstance_) {
pInstance_ = new Singleton;
}
return *pInstance_;
}
위의 코드는 Singleton 클래스 구현 중 Instance() 부분입니다. 하지만 위의 코드는 multi-thread 환경에서 사용될 경우 race condition이 발생할 수 있습니다. |
|
2002.05 |
|
|
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가 추가될 때마다 변경되어야 합니다. |
|
iwongu.05.07. |
class Gadget {
public:
void wait() {
while (!flag_) {
Sleep(1000);
}
}
void wakeup() {
flag_ = true;
}
private:
bool flag_;
};
위의 클래스는 multi-thread 프로그램에서 사용되기 위해 작성된 코드입니다. |
|
2002.04 |
|
|
ScopeGuard - exception_spec |
|
|
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입니다. |
|
ScopeGuard - andrei |
|
|
Pimpl idiom - headers |
|
|
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에는 어떤 문제가 있을까요? |
|
Static member initialization - trans_unit |
|
|
ScopeGuard - session_guard |
|
|
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의 사용 권한을 획득한 후 사용이 끝나면 두번째 함수를 호출하여 자원을 반납해야 합니다. |
|
std::auto_ptr - typed_buffers |
|
|
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 검사 속도를 개선하기 위해서 위와 같은 비트 연산을 사용하고 있습니다. |
|
2002.03 |
|
|
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() 함수 호출은 어떤 함수를 호출하게 될까요? |
|
NVI (Non-Virtual Interface Idiom) - link |
|
|
iwongu.03.24. |
class Rectangle { /* ... */ }
class Square : public Rectangle { /* ... */ }
Class 구조를 설계하다보면 class들간의 관계를 어떻게 정의해야 할지 결정하기가 어려운 경우가 많이 있습니다. |
|
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를 고려한다면 어떻게 구현해야 할까요? |
|
Pimpl idiom - 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를 반환해야 합니다. 하지만 이러한 작업이 항상 말만큼 쉽지는 않죠. |
|
iwongu.03.10. auto_ptr.03.14 headers.04.14 |
class Widget {
public:
// ... functions
protected:
// ... functions
private:
class WidgetImpl* pimpl_;
};
기존의 코드를 보시면서 pimpl_이라고 이름 붙여진 private pointer 변수를 보신적이 있으신가요? |
|
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 함수의 선언에는 어떤 것들이 있을까요? |
|
Static member initialization iwongu.03.03. trans_unit.04.12 |
// Widget.cpp int Widget::state_; 위와 같은 코드를 보시고 class의 static member 변수의 초기화를 안했다고 생각하고 있진 않으신가요?. |
|
NVI iwongu.03.03. link.03.24 |
class Widget {
public:
virtual int Process(Gadget&);
virtual bool IsDone();
// ...
};
누군가 base class로 사용하기 위해 위와 같은 코드를 작성했다면 과연 어떤 문제가 있을까요? |
|
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()는 각각 어느 함수들을 호출하게 될까요? |
|
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;
}
}
위의 코드와 같은 단순 루프를 더욱 최적화하려면 어떻게 해야 할까요? |
| 2002.9.30. | 잘못된 부분에 대해서는 저에게 메일 부탁드립니다. |