C++에서 프로퍼티 구현하기 #


C++에서 템플릿을 이용한 프로퍼티를 구현한 소스입니다.
VC++에서는 프로퍼티를 컴파일러 차원에서 지원하지만 이건 ANSI 코드입니다.

출처는 BorlandForum 이고 보다 안정적이게 소스를 수정했습니다.

#ifndef __PROP_H__BY_CDECL__ 
#define __PROP_H__BY_CDECL__ 

namespace Glass {

class IYES {};
class YES : public IYES {};
class NO {};

template <class T, class Parent, class ReadWrite = YES>
    class Prop
{
public:
    typedef Prop<T, Parent> this_type;
    typedef T (Parent::*get_fun)();
    typedef void (Parent::*set_fun)(const T&);

    Prop() : getf_(NULL), setf_(NULL), parent_(NULL) {}

    void SetParent(Parent *p) {
        parent_ = p;
    }

    void Set(set_fun f) {
        ReadWrite yn;
        IYES *p = &yn; // 읽기전용일때 이함수를 사용하면 컴파일 에러 !! 

        setf_ = f;
    }

    void Get(get_fun f) {
        getf_ = f;
    }

    T operator=(const T &value) {
        ReadWrite yn;
        IYES *p = &yn; // 읽기전용일때 이함수를 사용하면 컴파일 에러 !! 

        if (!setf_) {
            throw exception();
        }

        (parent_->*setf_)(value);
        return value;
    }

    T operator=(this_type &type) {
        return operator=(static_cast<T>(type));
    }

    operator T() {
        if (!getf_) {
            throw exception();
        }

        return (parent_->*getf_)();
    }

private:
    Parent *parent_;
    get_fun getf_;
    set_fun setf_;

};


} // namespace Glass 

#endif // __PROP_H__BY_CDECL__ 



#include <iostream>
#include <string>
using namespace std;


class AA
{
public:
    AA() {
        Str.SetParent(this);
        Str.Set(&AA::setStr);
        Str.Get(&AA::getStr);
    }

    void setStr(const string &str)
    {
        cout << "setStr" << endl;
        str_ = str;
    }

    string getStr()
    {
        cout << "getStr" << endl;
        return str_;
    }

    Glass::Prop<string, AA> Str;
    string str_;
};


int main()
{
    AA a;
    a.Str = "cdecl ";

}

'Dev > C++' 카테고리의 다른 글

memory pooling - code  (0) 2008.05.01
Is Derived - code  (0) 2008.05.01
boost::pool 예제  (0) 2008.05.01
STLport 초간단 설치  (1) 2008.05.01
Stroustrup - The real interview  (0) 2008.05.01

boost::pool 예제 #

boost::pool을 사용한 메모리 풀링.
빈번한 메모리를 사용할때에 유용하다고 판단.

#include <iostream>
#include <string>
using namespace std;

#include <windows.h>
#include <boost/pool/pool.hpp>

class VM
{
public:
    void* operator new(size_t s)
    {
        return bpool.malloc();
    }

    void operator delete(void *p)
    {
        bpool.free(p);
    }

private:
    char sz[100];

private:
    static boost::pool<> bpool;
};

boost::pool<> VM::bpool(sizeof(VM));


class NVM
{
private:
    char sz[100];
};


template <class Ty>
DWORD PoolingTest()
{
    enum { COUNT = 1000, LOOP = 500 };

    DWORD dw = GetTickCount();
    Ty *pArr[LOOP];

    int i, j;
    for (i = 0; i < COUNT; ++i) {
        for (j = 0; j < LOOP; ++j) {
            pArr[j] = new Ty();
        }
        for (j = 0; j < LOOP; ++j) {
            delete pArr[j];
        }
    }

    return GetTickCount() - dw;
}


int main()
{
    cout << "pooling: " << PoolingTest<VM>() << endl;
    cout << "normal: " << PoolingTest<NVM>() << endl;

    cout << "END" << endl;
    cin.get();
    return 0;
}



컴파일 환경
CPU: P3 600 (notebook)
RAM: 320

gcc version 3.4.1 (mingw special)

결과
pooling: 100
normal: 581
END

'Dev > C++' 카테고리의 다른 글

Is Derived - code  (0) 2008.05.01
C++에서 프로퍼티 구현하기  (0) 2008.05.01
STLport 초간단 설치  (1) 2008.05.01
Stroustrup - The real interview  (0) 2008.05.01
qsort vs sort  (0) 2008.05.01

STLport의 사용이유 #

  • VC++ 6.0의 내장된 STL 구현이 비표준인것들이 많아 사용상 어려움
  • 부분적으로 내장된 STL보다 성능이 뛰어남
  • VC++ 7.0 이후 버전은 개인적으로 자체 STL사용 권장


STLport 초간단 설치 #

STLport의 설치방법중 커맨드명령(IDE 없이)을 통해 설치하는 방법을 이용한다.
(개인적으로 이방법이 가장 편하고 쉬움)

VC++ 6.0을 사용할때 서비스팩은 항상 설치 권장
  • sp5 or sp6


STLport 받기 #

아래의 사이트에서 Current release version파일을 받음
받은 압축된(gz이나 zip파일) 파일을 아무데나 풀기


컴파일하기 #

압축을 푼 디렉토리에서 src디렉토리로 이동하여 컴파일 한다.
nmake -f vc6.mak 

컴파일후 lib 디렉토리가 생성되며 lib디렉토리에는 컴파일된 결과물인 Object파일과 lib, dll 파일들이 생성된다.


설치하기 #

nmake -f vc6.mak install

VC++의 환경변수를 세팅 안했다면 아래와같은 메세지가 나올것이다
Microsoft (R) Program Maintenance Utility   Version 6.00.9782.0
Copyright (C) Microsoft Corp 1988-1998. All rights reserved.

하위 디렉터리 또는 파일 ..\\lib이(가) 이미 있습니다.
하위 디렉터리 또는 파일 ..\\lib\\obj이(가) 이미 있습니다.
하위 디렉터리 또는 파일 ..\\lib\\obj\\VC6이(가) 이미 있습니다.
"Please set up MSVCDir environment variable. Did you run vcvars32.bat ?"
지정된 파일을 찾을 수 없습니다.
NMAKE : fatal error U1077: 'if' : return code '0x1'
Stop.

VC++의 환경변수를 세팅한다
vcvars32.bat

그리고 다시 install
nmake -f vc6.mak install
Setting environment for using Microsoft Visual C++ tools.
E:\Library\공개라이브러리\STLport-4.6\src>nmake -f vc6.mak install

Microsoft (R) Program Maintenance Utility   Version 6.00.9782.0
Copyright (C) Microsoft Corp 1988-1998. All rights reserved.

하위 디렉터리 또는 파일 ..\\lib이(가) 이미 있습니다.
하위 디렉터리 또는 파일 ..\\lib\\obj이(가) 이미 있습니다.
하위 디렉터리 또는 파일 ..\\lib\\obj\\VC6이(가) 이미 있습니다.
Copying STLport .lib files to VC lib directory : E:\PROGRA~1\MICROS~1\VC98\lib..
.
..\\lib\stlport_vc6.lib
..\\lib\stlport_vc6_static.lib
..\\lib\stlport_vc6_stldebug.lib
..\\lib\stlport_vc6_stldebug_static.lib
        4개 파일이 복사되었습니다.
Done copying .lib files.
Copying STLport DLLs to Windows system directory...
..\\lib\stlport_vc646.dll
..\\lib\stlport_vc6_stldebug46.dll
        2개 파일이 복사되었습니다.
STLport DLL libraries are installed on your system.
Copying STLport headers files to VC include directory : E:\PROGRA~1\MICROS~1\VC9
8\include\stlport...
414개 파일이 복사되었습니다.
Done copying STLport headers.
STLport installation complete.
Please find STLport headers in E:\PROGRA~1\MICROS~1\VC98\include\stlport.
Please find STLport .lib files in E:\PROGRA~1\MICROS~1\VC98\lib.
Please find STLport DLLs in Windows system directory.


설치내용 #

설치(install)의 경우 다음과 같은 내용이 실행된다.
  1. 윈도우의 System디렉토리에 다음 2개의 dll을 복사한다.
    • stlport_vc646.dll (릴리즈용)
    • stlport_vc6_stldebug46.dll (디버그용)

  2. VC 6.0 의 lib 디렉토리에 lib파일 4개를 복사한다.
    • stlport_vc6.lib (릴리즈용 DLL)
    • stlport_vc6_static.lib (릴리즈용 static)
    • stlport_vc6_stldebug.lib (디버그용 DLL)
    • stlport_vc6_stldebug_static.lib (디버그용 static)

  3. VC 6.0 include 디렉토리 밑에 stlport 디렉토리를 복사한다.


사용하기 #

VC++ 6.0 IDE의 include 경로를 잡아준다. (한번만 해주면됨)
  • Tools -> Options 메뉴에서 include 디렉토리를 VC++ 6.0의 include디렉토리 밑의 stlport디렉토리를 새로만들어 맨위로 올려준다
    • ex) E:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\VC98\INCLUDE\STLPORT

  • STLport를 사용하지 않을때는 stlport 디렉토리는 맨밑으로 내린다.

Use run-time library 를 지정한다.
  • 프로젝트마다 지정한다.
  • Project -> Settings -> C/C++ (탭) -> Category를 Code Generation -> Use run-time library:
  • 아래의 4개중 하나를 지정한다.
    • Multithreaded
    • Multithreaded DLL
    • Debug Multithreaded
    • Debug Multithreaded DLL

  • Single-Threaded 나 Debug Single-Threaded는 링크시 심볼 출동로 링크에러가 남.


배포하기 #

static (Multithreaded or Debug Multithreaded)으로 컴파일을 했을 경우는 코드가 포함되므로 따로 배포 할것이 없다 - 대신 실행파일(혹은 DLL)의 바이너리 크기가 커진다.

DLL 버전 (Multithreaded DLL or Debug Multithreaded DLL)으로 컴파일 했을경우 아래의 파일을 같이 배포해야한다.

(버전 4.6 기준)
Use run-time library 필요한 DLL
Multithreaded DLL stlport_vc646.dll
Debug Multithreaded DLL stlport_vc6_stldebug46.dll

'Dev > C++' 카테고리의 다른 글

C++에서 프로퍼티 구현하기  (0) 2008.05.01
boost::pool 예제  (0) 2008.05.01
Stroustrup - The real interview  (0) 2008.05.01
qsort vs sort  (0) 2008.05.01
최소 완전한 클래스를 만들어라  (0) 2008.05.01

실제 Stroustrup 인터뷰(The real interview) #


원문: B. Stroustrup, "The real Stroustrup interview," IEEE Computer, vol. 31, no. 6, pp. 110-114, June 1998.
번역문: 서진택의 C++ complete guide중에서 발췌

'The Design and Evolution of C++'(Addison Wesley, 1994)에서, Bjarne Stroustrup은 아래와 같이 논의했다.
"프로그래밍 언어는 실제로 세계(world)의 극히 작은 부분입니다. 그러므로 그것은 너무 심각하게 간주되어서는 안 됩니다. 일부분(proportion)의 감각(역자주: '프로그래밍 언어는 전 세계에 비하면, 매우 작은 부분이다'는 감각)을 유지하면서, 그리고 더욱 중요하게 유모어(humor) 감각을 유지해야 합니다. 중요한 프로그래밍 언어 중에서, C++는 익살과 농담의 풍부한 자원입니다. 그것은 우연이 아닙니다."
지난 몇 달 동안, Stroustrup과 IEEE Computer 잡지와의 가짜(hoax) 인터뷰가 사이버스페이스에서 회자(make round)되었다. 우리는 그 사건에 대해 유감스럽게 (regret) 생각한다. 하지만, 그것이 우리로 하여금 C++의 대부와, 표준 C++과 일반적인 소프트웨어 개발에 대한 그의 통찰력(insight)을 나눌 좋은 기회를 허락하였다. 우리는 또한 그의 지속적인 부분(proportion)과 유머(humor)에 대한 감각을 증명할 수 있었다(그는 그 우스꽝스러운 인터뷰를 만약 그 자신이 썼다면, 더 재미있는 개작(parody)이 되었을 거라고 제안했다).

- Scott Hamilton, Computer

표준 C++(STANDARD C++)

Computer: ISO(그리스어 isos의 파생어, International Organization for Standardization)는 표준 C++을 1997년 11월 승인하였습니다. 그리고 당신은 당신의 책 'The C++ Programming Language'(Addison Wesley, 1997)의 3번째 판을 출판하였습니다. 지난 몇 년간 C++가 어떻게 발전하였으며, ISO 표준이 C++ 공동체(community)에 무슨 의미를 갖는지 이야기해 주시겠습니까?

Stroustrup: 마침내 완벽하고(complete), 상세하며(detailed), 견고한(stable) C++의 정의를 내렸다는 것은 위대한 일입니다. 이것은 C++ 공동체에 직접적이고 간접적으로 무수한 도움이 될 것입니다. 컴파일러 제공자들은, 표준위원회의 내용들을 따라가는 것(catching up with the standards committee)에서 이제는 구현의 질에 관한 논쟁으로 쟁점을 이동시키기 시작함에 따라서, 분명히 우리는 더 좋은 개발 환경을 접하게 될 것입니다. 이것은 이미 진행중입니다.

표준을 수용하는 구현은 툴의 혜택과 큰 공통 플랫폼을 제공하는 라이브러리 제공자의 혜택을 경험하게 할 것입니다.

표준은 프로그래머에게 새로운 기술과 함께 더 도전적인 기회를 제공할 것 입니다. 제품의 코드에서 비실제적인 코드를 사용했던 프로그래밍 양식은 실제적인 계획(proposition)이 되어가고 있습니다. 이처럼, 더 유연하고(flexible), 일반적이고(general), 빠른(faster), 그리고 더 유지하기 쉬운 코드를 사용할 수 있습니다.

일반적으로, 우리는 냉정을 유지해야 하고, "개선된" 기교의 주연(orgy)에 탐닉(indulge)해서는 안 됩니다(역자주: 개선된 C++의 기교를 사용하는 것은 중요한 일이 아니라는 주장). 기적은 여전히 없습니다. 그리고 좋은 코드는 여전히 탄탄한 디자인과 대부분 직접적으로 매치되는 코드입니다. 그러나, 바로 지금은, 어떤 기교가 특정한 사람, 조직, 혹은 프로젝트에 적당한지, 실험하고 살펴볼 시간입니다. 'The C++ Programming Language'의 많은 부분은 이러한 기교와 그것들이 제공하는 흥정관계(trade-offs)를 기술하고 있습니다.

이러한 진보를 가능하게 하는, 우리가 눈으로 볼 수 있는 부분은, 언어의 새로운 큰 기능 - 템플릿(template), 예외처리(exception), 실행시 형 정보 (runtime type information), 이름공간(namespace) - 과 표준 라이브러리입니 다. 언어의 자세한 부분의 작은 개선 또한 중요합니다. 우리는 이제 여러 해 동안 사용 가능했던 유용한 것들을 대부분 가지게 되었습니다. 하지만, 호환성과 제품의 품질이 필요로 하는 곳에 대해서는 그것들에 크게 의존할 수 없었 습니다. 이것은 우리로 하여금, 우리의 라이브러리와 응용프로그램을 설계하는 데 있어서 최적이 아닌 차선(suboptimal)을 선택하도록 하였습니다. 그러나, 곧(올 해 1998년) 모든 큰 구현이 표준 C++를 탄탄하게 지원하게 될 것입니다.

언어와 프로그래밍 기교의 관점에서 C++에 가해진 가장 중요한 변화는, 정적으로 검사 가능한 형 안정성(staticaly verifiable type safety)에 대한 강조의 계속적인 증가와 템플릿의 증가된 유연성입니다. 유연한 템플릿은 우아함 (elegance)(역자주: 명시적인 형 변환이 필요없는 C++ 프로그램은 읽기 쉽다. 이것을 우아하다고 표현한 것 같다)과 효율성(efficiency)에 주목하는 형 안정성을 강조하기 위해서 필요합니다.

새로운 기술의 실행가능성(Feasibility of new techniques)

Computer: 당신은 말하기를 "숙련된 C++ 프로그래머조차도 지난 몇 년 동안 인지하지 못한 것은 그러한 새로운 기능이 아니라, 기본적인 새로운 프로그래밍 기교를 가능하게 하는 기능들간의 관계의 변화이다." 라고 하였습니다. 어떻게 이것이 표준 C++에 적용 가능한 지 몇 가지 예를 들어주시겠습니까?

Stroustrup: 오버로딩이나 템플릿이 함께 사용되어 우아하고 효과적인 형 안정 컨테이너의 중요한 역할을 한다는 것을 모르고도, 오버로딩과 템플릿은 규칙들을 각각 공부하는 것은 쉽습니다. 이러한 연결(역자주: 오버로딩과 템플 릿의 연결)은 컨테이너에서 공통적으로 많이 사용되는 근본적인 알고리즘을 자세하게 살펴볼 때에만 명확해 집니다. 다음의 프로그램 조각(segment)을 고려해 봅시다. count()의 첫 번째 호출은 정수 벡터에서 7의 횟수를 헤아립니 다. count()의 두 번째 호출은 스트링 리스트에서 "seven"의 횟수를 헤아립니다.

void f(vector<int>& vi, list<string>* ls)
{
int n1 = count(vi.begin(), vi.end(), 7);
int n2 = count(ls.begin(), ls.end(), "seven");
// ...
}

template<class Iter, class T>
int count(Iter first, Iter last, T value)
{
int c = 0;
while (first != last)
{
if (*first == value) c++;
++first;
}
return c;
}

오버로딩을 지원하는 각각의 언어에서 이것을 구현하는 방법은 다양합니다. 템플릿이 주어지면, 둘 모두의 호출을 다루는 하나의 함수를 만들 수 있습니다. 이 템플릿은 둘의 호출에 대해 최적으로 확장(역자주: 실제로 템플릿 함수는 호출되는 것이 아니라, 컴파일 시간에 템플릿을 호출한 문법에 따라 각각의 경우로 만들어진다. 그리고 실제로 만들어진 이 함수가 호출된다. 이것을 확장(expansion)이라 한다)될 것입니다. 이 count()는 표준 라이브러리의 count()와 거의 유사합니다. 그러므로 사용자가 count()를 직접 작성할 필요는 없습니다. count()함수는 그 자체가 오버로딩에 의존하고 있습니다: 명확히 등호 연산자 ==는 정수와 스트링에 대해 오버로딩되어 있습니다. 게다가 * 와 ++는 각각 벡터와 리스트를 위한 반복형(iterator type)을 위하여 "역참조 (dereference)"와 "다음 요소 참조"로 오버로딩되어 있습니다. 다시말하면, *와 ++는 포인터를 위해 그것들이 가지는 의미가 주어졌습니다.

count()의 이러한 정의는 C++ 표준 라이브러리의 컨테이너와 알고리즘에서 사용된 중요 기교의 결합을 설명합니다. 이러한 기교는 유용합니다. 그리고 그것은 오로지 기본적인 언어의 규칙으로는 간단하게 기술할 수 없습니다.

template<class Iter, class Predicatte>
int count_if(Iter first, Iter last, Predicate pred)
{
int c = 0;
while (first != last)
{
if (pred(*first)) c++;
++first;
}
return c;
}

bool less_than_7(int i) { return I < 7; }

void f2(vector<int>& vi, list<int>& li)
{
int n1 = count_if(vi.begin(), vi.end(), less_than_7);
int n2 = count_if(li.begin(), li.end(), less_than_7);
// ...
}

위에 제시된 좀 더 진보된 예를 참조해 봅시다. 값의 횟수를 헤아리는 대신에, count_if()는 predicate를 만족시키는 요소의 개수를 헤아립니다. 예를 들면, 위에서처럼 7보다 작은 값을 가지는 요소의 개수를 헤아릴 수 있습니다.

이러한 기교를 일반화하여, 어떠한 형의 어떠한 값도 비교하는 것을 다루기 위해서는 함수 객체(function object) - 아래처럼 객체가 함수처럼 불러 내어질(invoke) 수 있는 클래스 - 를 선언하는 것이 필요합니다. 아래처럼 생성자 비교를 원하는 값의 참조를 저장합니다. 그리고 () 연산자는 비교를 수행합니다. 바꾸어 말하면, vi에 있는 요소중에 7보다 작은 요소의 수를 헤아리고, ls에 있는 요소중에 "seven"보다 작은 요소의 수를 헤아립니다.

template<class T> class Less_than
{
const T v;
public:
Less_than(const T& vv) : v(vv) {} // constructor
bool operator() (const T& e) { return e < v; }
};

void f3(vector<int>& vi, list<string>& ls)
{
int n1 = count_if(vi.begin(), vi.end(), Less_than<int>(7));
int n2 = count_if(ls.begin(), ls.end(), Less_than<string>("seven"));
// ...
}

생성된 코드는 매우 효율적이며, 특별히 비교를 수행하고, 다음 요소를 가져 오는 등의 작업을 하는데, 함수 호출 - 혹은 비슷한 늦은 연산자 - 을 사용하지 않는다는 것(역자주: 자세한 사항은 '함수 객체'를 참고하라)은 언급할 만 합니다.

의심할 여지도 없이, 이 코드는 C++ 프로그래머가 아닌 사람에게, 혹은 템플릿과 오버로딩의 개념을 익히지 못한 C++ 프로그램머에게 조차도 이상하게 보일 것입니다. 물론 이것은 이 예제를 여기서 제시한 이유중의 일부입니다. 그러나, 진짜 의도(bottom line)는 이 기교가 당신에게 효율적이고, 형 안정적 이고, 일반적인 코드를 작성하게 한다는 것입니다. 함수형 언어(functional language)(역자주: LISP(list processing: 1959년 John McCarthy가 개발)같은 언어가 한 예이다)에 익숙한 사람들은 이러한 기교가 그러한 언어에서 선구적으로 개척된 기교와 유사하다는 것을 알아차렸을 것입니다.

언어의 모습은 분리되었을 때 근본적으로 지루합니다. 그리고 그것은 좋은 시스템 설계로부터 흩뜨릴 수 있습니다(오직 언어가 살아남아야 할 프로그래밍 기교의 측면에서).

표준 라이브러리(The Standard Library)

Computer: 표준 라이브러리는 어떻습니까? 또한 그것이 C++ 공동체에 무슨 영향을 끼칠까요?

Stroustrup: 표준 라이브러리의 가장 새롭고 흥미로운 부분은 컨테이너와 알고리즘의 일반적이고 확장 가능한 골격(framework)입니다. 그것은 종종 STL(Standard Template Library)이라고 불리는데, 근본적으로 Alex Stepanov의 작품입니다(그 당시 Hewlett-Packard에서 지금은 Silicon Graphics에 있다).

Alex는 확고하게(uncompromisingly) 일반적이면서 효율적인 근본적인 알고리즘을 제공하기 위해 일을 했습니다. 예를 들면, 자료 구조에서 요소를 찾는 것, 컨테이너를 정렬하는 것, 자료 구조에서 값의 횟수를 헤아리는 것 등입니 다. 그러한 알고리즘은 많은 계산에서 근본적인 것입니다.

Alex는 많은 종류의 언어를 가지고 연구했습니다. 그리고 몇 년간 공동 연구자들이 있었습니다. 주목할만한 이들은 David Musser(Rensselaer Polytechnic Institute), Meng Lee(HP Labs), Andrew Koenig(AT&T Labs) 등 입니다. 제가 STL에 공헌한 부분은 매우 작지만 중요하다고 생각합니다: 저는 어댑터(adapter)라고 불리는 mem_fun()을 디자인했습니다. 그것은 다형 객체(polymorphic object)의 컨테이너를 위해서 표준 알고리즘이 사용되는 것 을 제공합니다(역자주: 어댑터는 크기가 동적인 가변 객체를 컨테이너 연산의 대상으로 하기 위한 메모리 할당 및 처리 루틴을 말하는 것 같다). 이처럼, 객체 지향 기술을 시도하는 것이 깔끔하게 표준 라이브러리의 일반적인 프로그래밍 골격에 포함되었습니다.

다소 놀랍게도, STL은 제가 몇 년 전에 개발한 C++을 위한 표준 컨테이너의 좋은 집합을 결정하는 판단기준과 일치되었습니다. 1년 후, STL에 대해 의논하고 마무리한 후, ISO C++ 위원회는 STL을 C++를 위한 표준 라이브러리의 중요한 부분으로 받아들였습니다. 저의 판단기준도 포함되었습니다.

간단한 기본 연산의 확고한 효율성(예를 들면, 배열의 인덱싱 (subscripting)이 함수 호출의 비용을 유발해서는 안 된다);

형 안정성(type-safety)(컨테이너로부터의 객체는 명시적인(explicit) 혹은 함축적인(implicit) 형 변환 없이 사용 가능해야 한다);

일반성(라이브러리는 벡터, 리스트, 맵 같은 몇 개의 컨테이터를 제공해야 한다);

확장성(내가 필요로하는 컨테이너를 라이브러리가 제공하지 못하는 경우, 내가 컨테이터를 만들어 표준 컨테이너처럼 사용할 수 있어야 한다).

약간의 수정과 추가를 거친 STL을 채택함으로써, 위원회에서 해야 할 끔찍한 디자인을 피할 수 있었습니다. 명확히, C++ 표준 위원회의 시간제 근무자의 그룹이 프로그래머가 유용하다고 판단하는 모든 라이브러리의 기능을 제공할 수 없습니다. 결과적으로 중요한 쟁점은 무엇이 표준 라이브러리에 포함되어야 하고, 무엇이 기업과 개인이 제공하는 것으로 남겨져야 하는 것을 결정하는 것이었습니다.

우리는 무엇이 포함되어야 하는가의 길잡이로 "독립적으로 개발된 라이브러리 사이의 통신 역할을 하는데 필요한 것"을 사용하기로 하였습니다. 이처럼, I/O, 스트링, 컨테이너가 큰 촛점이 되었습니다. 우리는 표준 C 라이브러리와 수 계산을 위한 몇 기능을 역사적인 이유 때문에 포함시켰습니다. 하지만, 잠재적으로 유용한 많은 기능들 - 날짜와 통화, 정규 표현 매칭, 그래픽 - 을 남겨두었습니다. 다행히도, 이러한 기능들은 공개 혹은 상업적으로 이용 가능합니다.

표준 라이브러리는 프로그래머가 바퀴를 다시 발명하는 것을 구해냅니다. 특별히, 표준 컨테이너는 초보자나 숙련자 모두에게 높은 수준의 프로그램 (high level programming)을 허락합니다. 쉬운 일을 간단히 처리하는, 아래의 간단한 프로그램을 고려해 봅시다.

int main()
{
cout << "Please enter your first name:\n";
string name;
cin >> name; // read into name
cout << "Hello" << name << "!\n";
}

매크로도 이용하지 않고, 명시적인 메모리 관리나 다른 고수준 언어의 기능을 이용하지 않으며, 리소스의 제한도 받지 않습니다. 특별히, 만약 어떤 익살꾼(joker)이 자신의 첫 번째 이름으로 30,000자를 적는다고 하더라도, 에러나 오버플로우 없이 프로그램은 충실히 이름을 출력할 것입니다.

표준 라이브러리를 이용하는 것은 C++가 배워지던 방법의 혁명을 일으킬 수 있고 일으켜야 합니다. 이제 C++을 고수준 언어로써 배우는 것이 가능합니다. 학생들은 이제 필요할 때만 낮은 수준의 프로그래밍 기능들을 다루면 됩니다. 혹은 낮은 수준의 프로그래밍 기능들을 언급할 적절한 실력들이 쌓이고 나서 보아도 됩니다. 이처럼, 표준 라이브러리는 도구와 교사로서의 역할을 할 것입니다.

복잡성, C++와 객체지향프로그래밍(COMPLEXITY, C++, AND OOP)

Computer: 'The C++ Programming Language'에서 당신은 말하기를 "정상적인 실용적인(practical) 프로그래머들은 생산성, 유지보수, 유연성과 어떠한 종 류와 스케일의 프로젝트에 대한 품질에 대해서도 놀랄만한 향상을 달성했다." 고 했습니다. 그러나 아직 몇몇 비평가들은 C++과 일반적인 OO는 여전히 너무 복잡하고, 교정 유지보수(corrective-maintenance)문제를 일으키며, 큰 시스템에서의 유지 문제가 있다고 합니다. 어쨌던 이러한 비평이, 당신 자신의 경험으로 볼 때, C++로 설계하는 큰 시스템의 개발에 적용되는 것이라 생각합 니까?

Stroustrup: 저의 개인적인 경험으로, OO 설계와 OO 프로그래밍은 전통적인 절차적인 방법을 통해서 당신이 얻을 수 있는 것보다 좋은 코드를 제공할 것 입니다. 그러한 코드는 더욱 유연하고(flexible), 더욱 확장 가능하며 (extensible), 심각한 수행상의 부하(overhead)없이 유지 보수 가능한 (maintainable) 코드입니다. 위의 개인적인 의견에 반대되는 제가 좋아할 만한 강한 증거는 없습니다. 하지만, AT&T 내부에서의 몇몇 연구와 다른 연구들은 이러한 의견을 지지합니다.

두 요소가 쟁점을 난처하게 합니다: "객체 지향적"인 것이 정말로 무엇인지에 대한 일반적인 동의가 없습니다. 또한 토론은 좀체 경험을 충분히 설명하지 못합니다. "OO의 문제"의 많은 부분은 정말로 OO가 무엇인지 모르는 부분적인 이해를 가진 사람들이 야망찬 프로젝트를 진행하는데서 비롯합니다.

그렇다면 OO는 무엇입니까? 확실히 좋은 프로그램 모두가 객체 지향적인 것은 아니며, 객체 지향적인 모든 프로그램이 좋은 것도 아닙니다. 만약 그렇다면 "객체 지향적"인 것이 단순히 "좋은 것"을 의미합니다. 그리고 이것은 당신이 실제적인 결정을 내려야 할 때 개념을 혼동하게 하는 하나의 추가된 전공용어(buzzword)에 불과합니다. 저는 OOP를 클래스의 상속과 가상함수(어떤 언어에서는 메서드(method)라고 하는)를 많이 사용한 프로그램과 동일시하곤 합니다. 이 정의는 역사적으로는 정확합니다. 왜냐하면, 클래스 계층과 가상 함수는 그 당시 시뮬라(Simula)와 다른 언어를 구분짓는 철학이었기 때문 입니다. 사실, Smalltalk가 가장 중요하게 강조된 것은 시뮬라 유산의 이러한 관점 때문입니다.

클래스 계층과 가상 함수에 기초하여 OO를 정의하는 것은 OO가 성공할 것 같은 곳으로의 몇 지침을 제공하기 때문에 실용적입니다. 당신은, 정확하게 같은 형이 아니지만 공통의 인터페이스로 조작될 수 있는 객체를 위한, 구현을 공유할 수 있는 개념들의 변체(variant)를 위한 계층적인 순서를 가진 개념들을 찾습니다. 몇 예제와 약간의 경험을 한다면, 이것이 디자인을 위한 매우 강 력한 접근의 기초가 되는 것을 알것입니다.

그러나, 모든 개념이 자연스럽고 유용하게 계층(hierarchy)과 적합한 것은 아닙니다. 개념들간의 모든 관계가 계층적인 것도 아니고, 모든 문제에 대해 객체에 중심한 접근이 최선인 것도 아닙니다. 예를 들면, 몇 문제들은 근본적으로 알고리즘적(algorithmic)입니다. 결론적으로, 일반 목적의 프로그래밍 언어는 다양한 사고와 다양한 프로그래밍 스타일을 지원해야 합니다. 이러한 다양성은 풀이해야 할 문제의 다양성과 문제 풀이의 다양성에 기인합니다. C++ 은 다양한 프로그래밍 스타일을 지원합니다. 그러므로, 객체 지향 언어라기 보다는 멀티패러다임(multiparadigm) - 이름을 꼭 붙여야 한다면 - 언어라고 불 리는 것이 더 적당합니다.

"좋은 것" - 이해하기 쉽고, 유연하고, 효율적인 - 의 기준을 대부분 만족시키는 디자인의 예로 전통적인 절차 코드를 사용한 재귀 경향 파서(recursive descent parser)가(역자주: 실행 가능한 코드를 생성하는 번역기를 파서 (parser)라 하는데, 재귀 호출을 사용하며, 주로 수식을 번역하기 위해 사용한다) 있다. 다른 예로 STL이 있습니다. 이것은 전통적인 절차적인 코드와 파라미터적인 다형성(역자주: 이름에 의한 다형성이 아닌)에 전적으로 의존하는 컨테이너와 알고리즘을 포함한 일반 라이브러리입니다.

저는 단 하나의 프로그래밍 패러다임만 지원하는 언어는 제한적이라는 것을 발견했습니다. 그것은 간단함(simplicity)을 사는 대신, 프로그래머에게 구속복(straitjacket)을 입히거나, 언어의 복잡함을 응용 프로그램의 복잡함으로 전가 시킵니다. 이것은 특정 목적 언어(special-purpose language)에는 적합하지만, 범용 언어(general-purpose language)에는 적합하지 않습니다. 저는 종종 C++를 시스템 프로그래밍으로 편향된 범용 언어라고 특징 지웁니다. 다음을 지원하는 "더 나은 C"로 생각하는 것이죠.

데이터 추상화

객체 지향 프로그래밍

일반적인 프로그래밍(generic programming).

자연히, 이것은 하나의 접근법만을 허용하는 언어에 비해 복잡함을 증가시킵니다. 저는 이러한 관점 - 문제 영역마다 최선인 각각의 디자인과 프로그래밍 접근법이 있다 - 이 어떤 이들을 화나게 한다는 것을 주목했습니다. 확실히, 모든 사람에게 혹은 모든 문제에 올바른 한가지 방법이 있다는 관점은 거절합니다. 세계는 근본적으로 간단하다는 사실을 열정적으로 믿고 싶어하는 사람들은 제가 이것을 단지 프로그래밍 언어에 대해서만 적용한다는 사실과는 상관없이 격노(fury)합니다. 결국, 프로그래밍 언어는 시스템을 설계하기 위한 많은 도구들 중의 하나입니다.

이러한 두 관점을 모두 해결하는 이상적인 방법은 모든 프로그래밍 스타일을 효율적으로 지원하는 간단한 프리미티브(primitive)의 집합을 지원하는 언어를 가지는 것입니다. 이것이 반복적으로 계속 시도되기는 했지만, 달성되지는 - 저의 의견에 - 못했습니다.

자바와 C++(JAVA AND C++)

Computer: 위에서와 같은 논쟁이 납득할만하게 자바(Java)로 확장 가능하다고 봅니다. Sun이 주장하기를 700,000명의 자바 프로그래머가 있다고 합니다 (비교해서 C++ 프로그래머는 1,500,000명 정도). 당신은 C++가 C와 호환될 필요도 없으며, 자바가 당신이 고안한 언어가 아니라는 주장을 고집합니다. 이러한 질문을 1000번 이상 받았다면 당신은 무슨 말을 할 것입니까?


Stroustrup: 오늘날, 저는 항상 자바에 대해서 질문 받습니다. 그리고 항상 대답하기는 어렵습니다. 제가 만약 약간 부정적인 것을 말한다면, 무례한 것으로 느껴집니다. 제가 만약 약간 긍정적인 것을 말한다면, 자바를 둘러싼 상업적인 공간(commercial hype)에 뛰어드는 것 같고, 자바 공동체의 부분으로부터 흘러나오는 불운한 반 C++ 선전(the unfortunate anti-C++ propaganda)에 뛰어드는 느낌이 들기 때문입니다.

저는 사람들에게 상업적인 라이벌 상태가 아닌, 자신이 개발해야 하는 디자인 기준에 따라 두 개의 언어 중 적절한 것을 선택하라고 권장합니다. 저는 C++을 위한 디자인 표준(cirteria)을 'The Design and Evolution of C++'에서 개괄해 놓았습니다. 그리고 자바는 이러한 기준을 만족시키는 시작조차 못하고 있습니다. 자바를 만병통치약으로 생각하지 않고 프로그래밍 언어의 하나로 생각하는 것은 좋습니다. 결국, C++는 자바의 디자인 목표와 완벽하게 일치하지 않습니다. 그러나, 자바가 유일한 프로그래밍 언어로써 진급된다면, 자바의 결함과 제한은 심각하게 될 것입니다. C++을 개발하는데 적용된 기준이 자바에는 적용되지 않는 몇 가지 예가 아래에 있습니다.

서로 다른 언어로부터 쓰여진 프로그램 부분들을 효과적으로 조합하는 능력

다양한 디자인 스타일과 프로그램 스타일

기정의 타입(built-in type)과 맞먹는 효율을 가진 사용자 정의 타입

기정의 타입과 사용자 정의 타입의 일관된 처리(treatment)

STL처럼 실행시 부담없는 일반 컨테이터(generic container)를 사용하는 능력

프로그래머들이 우아하고 효율적인 코드를 작성할 수 있도록 제가 C++을 디자인했습니다. 많은 응용프로그램을 위해서, 우아함과 효율성을 타협하기를 원하지 않을 때 C++은 여전히 최상의 선택입니다.

저는 어떻게 사람들이 "프로그래머"를 세는지 의문입니다. 학생이 프로그래머입니까? PC에 컴파일러를 가진 사람은 모두 프로그래머입니까? 저는 C++ 을 위해서 인용된 숫자를 이해합니다. 그것은 보수적이고 그럴듯합니다. 그것은 지난 해 실제 팔린 금액을 위한 C++ 프로그램의 수를 적절히 근사화한 것 입니다. 저는 Sun에서 주장하는 자바 프로그래머의 수가 같은 근거인지 의문입니다. 부수적으로, 컴파일러 판매, 책 판매, C++ 수강생 수 등의 확실한 수에 근거해서, 제가 추측하기로 C++ 프로그래머는 매년 10%∼20%증가하고 있습니다.

그리고 저는 자바 팬(fan)이 아닙니다. 저는 과대 선전(hype)을 싫어합니다. 저는 프로그래머가 아닌 사람에게 프로그래밍 툴을 판매하는 시장 전략을 싫어합니다. 저는 독점적인 언어를 싫어합니다. 그리고 저는 많은 프로그래밍 언어를 좋아합니다. 기술적인 측면에서, 자바는 저에게 다른 언어에서 받았던 것처럼, "와 깔끔한데!"란 인상을 주지 못했습니다. 자바는 제가 생각하기에 제 한적인 형태로 다른 유명한 언어의 기능들을 제공합니다.

자바는 많은 것을 C++로부터 빌려 왔습니다. 하지만 그렇게 많이는 아니며, 원하는 만큼의 이해와 맛(taste)도 빌려오지 못했습니다. 자바를 위한 중요한 약속들을 지키기 위해선, 자바는 성장해야 합니다. 이러한 전개는 'C++보다 간단하게'라는 자바의 주장과 타협할지도 모릅니다. 그러나 저의 추측에 그러한 노력은 현재의 것보다 더 좋은 자바 언어를 만들 것입니다. 현재, 자바는 언어의 특징들과 "표준" 라이브러리를 꽤(quite a pace) 축적하고 있는 것처럼 보입니다. 저는 자바 버전의 템플릿이 나타날 것을 기대하고 있습니다.

자바와 그의 공동체가 성숙해가면서, 활기있고 활기있게 하는 철학 (live-and-let-live philosophy)을 희망적으로 채택할 것입니다. 이것은 자바가 프로 프로그래머들의 소중한 도구(tool chest)중의 한 언어로 자리잡게 할 것 입니다.

도구(TOOLS)

Computer: 지난 몇 년간 어떤 방법으로 시스템이 변화했습니까? 그리고 C++의 활동범위(arena)와 일반적인 시스템 디자인에 무엇이 더 필요합니까? C++가 비교적 성장한 이 시점에서, 사용할 수 있는 C++ 툴(tool)들을 어떻게 평가하겠습니까? 그리고 여전히 개선되어야 하는 것은 어떤 것들입니까?


Stroustrup: 먼저, 컴파일러, 디버거, 프로파일러(profiler)(역주: 프로그램의 성능 분석을 위한 도구), 데이터베이스 인터페이스, GUI(Graphical User Interface) 빌더, CAD(Computer Aided Design) 툴과 ISO 표준을 지원하는 기타 기본 툴들을 살펴보고자 합니다. 예를 들면, 저는 데이터베이스 질의의 결과를 STL 컨테이너 혹은 적절한 객체형의 istream으로 얻고 싶습니다. 툴 벤더(vendor)는 좋은 출발을 하였습니다. 하지만, 컴파일러나 다른 소스 코드 분석기에 의존적인 작업을 너무 많이 하였습니다.

제가 리스트한 기본 도구들은 무엇이 바뀐지에 대한 부분적인 대답에 불과합니다. 과거 몇 년 동안, 많은 수의 프로그래머들이 훌륭한 도구와 시스템 기능을 제공하는 인터페이스 코드에 의존해 왔습니다. 이러한 도구들은 지루하고, 에러 발생이 쉬운 작업으로부터 프로그래머들을 구제하는데 필수적입니다. 하지만, 프로그래머가(혹은 고용인이) 툴 제공자의 포로가 되는 위험에 처해 있습니다.

종종 이러한 도구들은 전통적인 프로그래밍 언어에 비해 더욱 복잡하며, 표준은 거의 없습니다. 저는 독점성이(nonproprietary) 없는 도구와 라이브러리를 추천하고 싶습니다. 짧은 안목으로 보면, 예를 들면 10년 정도, 많은 그러한 표준은 형식적인 ISO 나 IEEE의 표준보다 산업계의 표준역할을 합니다. 하지만, 건강한 소프트웨어 산업을 위해, 중요 인터페이스는 잘 정의되고 대중이 사용할 수 있는 것이 필수입니다.

COM(Component Object Model)이나 CORBA(Common Object Request Broker Architecture)같은 시스템 레벨 객체를 위한 표준의 중요성이 증가하는 가운데, C++가 그러한 것들과 깨끗하고(clean), 잘 문서화되어, 사용하기 쉽게 결합될 수 있는 것은 특별히 중요합니다. 불행하게도, 그러한 "표준 작업" - 모두에게 이로운 - 은 누구에게도 짧은 안목의 이점을 제공하지 않기 때문에 소흘히 됩니다.

저는 사용 가능한 C++ 툴들을 평가하지 않겠습니다. 그것들은 매우 훌륭하며, 다른 언어의 어떤 툴보다 더 좋습니다. 그러나, 프로그래머로서, 저는 당연히 더 좋은 품질의 툴들을 바랍니다. 개인적으로, C++ 소스코드를 분석하는 더 좋은 툴들을 기대하고 있습니다. 저는 또한 C++ 컴파일러 벤더들이 신제품을 개발하는 것보다, 자사 컴파일러의 품질과 수행 능력을 향상시키는데 예산을 조금 더 투자하기를 기대합니다. 컴파일러의 실제적인 성능향상은 새로운 버전의 완전한 C++ 컴파일러를 위한 시간보다 다소 저렴합니다. 그러나, 중요한 사용자들이 적응 테스팅(conformance testing)이나 벤치마킹 (benchmarking)을 요구하는 것을 시작하지 않는다면, 벤더들이 광고상 좋게 보이는 것을 위해 자원을 사용할 것을 느낍니다.

미래(THE FUTURE)

Computer: 저는 당신이 C++표준화 작업에 많이 참여한 것으로 알고있습니 다. 하지만, 현재 당신이 참여한 다른 프로젝트에는 어떤 것이 있으며, C++을 발전시키기 위해 어떤 작업을 계속할 것입니까?


Stroustrup: 나는 매우 큰 프로젝트를 성공적으로 완성하고 나서 고통받고 있습니다. ISO C++ 표준이 완성되었습니다. 'The C++ Programming Language'의 제 3판에는 표준 C++이 무엇을 제공하는지 어떻게 가장 잘 사용하는지 진지한 프로그래머들에게 알리고 있습니다. 그리고 'The Design and Evolution of C++'은 C++에 장착된(shaped) 디자인 결정들을 문서화하고 있습니다. 해야할 것들이 아직 많습니다. 그러나 전시간 언어 디자이너를 필요로 하는 것은 아무것도 없습니다. 이제 가능한 변화들에 집중하기 보다는, 코드를 작성함 으로써 C++의 힘과 유연성을 즐길 시간입니다.

그것과는 별도로, 저는 몇 가지 사실들을 배울 기회를 얻었습니다. 몇 새로운 언어와 큰 사업에서 소프트웨어가 어떻게 사용되는지에 관한 것이 그것입니다. 그리고 분산 컴퓨팅에서 몇 실험들을 계획중입니다.

'Dev > C++' 카테고리의 다른 글

boost::pool 예제  (0) 2008.05.01
STLport 초간단 설치  (1) 2008.05.01
qsort vs sort  (0) 2008.05.01
최소 완전한 클래스를 만들어라  (0) 2008.05.01
RAII (Resource Acquisition Is Initialization)  (1) 2008.05.01

std::sort 는 qsort 보다 빠르다 #


  1. 비교 함수의 리턴값
    • <qsort>
      qsort의 비교함수 리턴 값은 int type 입니다.
      그러므로 결과는 3가지 종류이죠

      a < b -> -1
      a > b -> 1
      a = b -> 0

      그러므로 적어두 2번을 비교 해야 합니다.


    • <sort>
      sort의 비교함수 리턴 값은 bool type이입니다.
      그러므로 1번만 비교 하면 되는것이져

         template <typename T>
         bool comp(const T &a, const T &b) {
             return a < b  // a가 b보다 작으면 참 아니면 거짓 
         }
      


  2. 비교함수의 inlining
    • <qsort>
      비교자를 함수로 밖에 못넘기기때문에 함수호출로 인한 오버헤드는 불가피 합니다.
      만약 비교함수를 inline으로 선언해도 함수 포인터를 사용 하므로 무시됩니다.
      (inline및 register는 힌트이기 때문에 컴파일러의 사정에 따라 무시될수 있습니다. 야속하게도 ...)

    • <sort>
      비교함수및 sort함수가 template으로 구성되어서 함수및 함수객체(functor)를 비교자로서 넣을수 있습니다.
      함수로 넣으면 qsort와 같은 오버헤드가 발생 하겠지만 함수객체로 만들면 inlining이 가능하게 만듭니다.



  3. swap 함수의 대입
    • <qsort>
      qsort의 swap함수는 void*로 인수를 받기 때문에 실제 데이터의 크기과 정보를 알수가 없습니다
      그래서 qsort함수의 3번째 인자(데이터의 크기)를 기준으로 객체의 혹은 타입의 크기만큼 전체 복사를
      하게 구현 됩니다.


    • <sort>
      sort함수의 경우는 복사입니다 (template 때문에 가능하져)

         template <typename T>
         void swap(T &a, T &b) {
             T t = a;
             a = b;
             b = a'
         }
      

      그러기 때문에 프로그래머의 데이터 객체의 대입연산자 구현에 따라
      성능은 많이 나아질 여지가 충분한것이져

      거기다가 데이터 자체가 Reference Counting이 된는 객체라면
      그 성능은 월등할것 입니다.

'Dev > C++' 카테고리의 다른 글

STLport 초간단 설치  (1) 2008.05.01
Stroustrup - The real interview  (0) 2008.05.01
최소 완전한 클래스를 만들어라  (0) 2008.05.01
RAII (Resource Acquisition Is Initialization)  (1) 2008.05.01
상속되지 않는것  (0) 2008.05.01

OOP는 능숙되지 않은 프로그램머에게 나쁜프로그램을 못하게 하는 것이다 #


OOP는 데이터와 그 데이터를 조작하는 오퍼레이터를 캡슐화 함으로서
은닉화를 통한 데이터 보호와 추상화를 통한 인터페이스 노출, 상속을 통한
코드 재활용으로 견고하고 융통성있는 프로그램을 만들기 위한 좋은 개념입니다.
그 구체화된 도구가 class 입니다.


최소 완전한 class를 만들어라 #

Effective C++에서는" 최소 완전한 class를 만들어라 " 라고 얘기 하고 있습니다.
이 얘기는 첨에 이야기한 나쁜프로그램을 못하게하는 것과 일맥 상통하는 내용입니다.
작은 클래스라도 최소 인터페이스라도 완전한 클래스를 구현하는 내용입니다.

그 내용에는 다음과 같은 것들이 있을것입니다.
  • 생성
  • 소멸
  • 복사및 대입
  • 상속


생성 #

디폴트 생성자는 클래스의 기본적인 동작을 하는 내용을 담은 생성자 입니다.
이것은 기본적인 객체의 생성을 도와주고 동적배열 생성과 같은 행동에도 쉽게 문제를 해결해 줍니다.
class Item
{
public:
   Item();  // 디폴트생성자 - 구현생략 
};
허나 id와 같은 값이 필수인 객체를 생성할때 디폴트 생성자를 허용한다면
모든 멤버함수에서 id의 유효성을 검사하는 코드가 난무하거나
혹은 없는 id를 참조하는 불상하는 낼수도 있을것입다.

이럴땐 불편함(?)을 감수해서라도 디폴트 생성자를 제거하는것이 낳을 것입니다.
class Person
{
public:
   Person(int nID) : nID_(nID) {}  // 디폴트 생성자 없음 
private:
   int nID_;
};
그리고 한개의 인수를 가지는 생성자는 암시적인 형변환이 되므로
만약 암시적인 형변환때문에 문제의 소지가 발생할 여지가 있다면
다음과같이 explicit 키워드를 이용해 암시적인 형변환을 막는 것이 좋습니다.
class Person
{
public:
   explicit Person(int nID) : nID_(nID) {}
private:
   int nID_;
};

Person p;
p = 78; // explicit은 이 행동을 막아줍니다. 

만약 Factory Method 같은 패턴을 사용하기위해
정상적인 객체의 생성을 막을려면 디폴트 생성자를
private이나 protected로에 위치시키므로서 해결할수 있습니다.
class NoCreate
{

protected:
        NoCreate() {}
};


소멸 #

생성자에서 혹은 멤버함수에서 생성한 리소스는
항상 소멸자에서 가비지 콜렉션을 해주어야합니다.


복사및 대입 #

복사와 대입은 일관된 정책을 사용합니다
복사생성자가 존재한다면 대입연산자도 만들고
복사생성자가 존재하지 않는다면 대입연산자도 만들지 않습니다.

이유는 객체의 일관성과 일반화된 인터페이스를 제공해 주기 위함입니다.
class Item
{
public:
        Item(const Item& t);        // 복사생성자 
        Item& operator(const Item& t); // 대입연산자 
};

Item::Item(const Item& t)
{
}

Item& Item::operator(const Item& t)
{
        // 재귀치환을 검사합니다. 
        // 재앙을 막아줍니다. 
        if (this == &t) return *this;

        reutrn this;
}

만약 복사와 대입이 필요없다면 다음과같이
객체의 복사도 대입을 막아줍니다.

class NoCopy
{
public:
        NoCopy() {}

private:
        // 두가지 수단으로 함수호출을 저지합니다. 
        // 첫번째는 private 로 선언하여 외부의 노출을 막습니다. 
        // - 컴파일러가 사용을 막아줍니다. 
        // 두번째는 구현을 하지 않습니다. - 링커가 사용을 막아줍니다. 
        NoCopy(const NoCopy& t);        // 복사생성자 
        NoCopy operator(const NoCopy& t); // 대입연산자 
};



상속 #

만약 기초클래스의 용도로 사용될것이라면 소멸자에
virtual 키워드를 추가 하십시요
class Interface
{
public:
        virtual void MemberFunction() = 0;        // 순수가상함수 
        virtual ~Interface() {}
};

기초클래스의 포인터나 참조로 상속된 객체를 핸들링 할때
상속된 클래스의 소멸자가 호출 안되는 재앙을 막을수 있습니다.

Effective C++에 의하면 상속을 막는다면 문서로서 표시하지 말고
문법적으로 상속을 맞는 방법을 택하라고 되어 있습니다.

class Base
{
private:
        Base() {}

public:
        ~Base() {}
};


class Drived : public Base        // private 생성자가 상속을 막아줍니다. 
{};

void main()
{
        Drived d;                // (x) 에러 입니다. 

}


'Dev > C++' 카테고리의 다른 글

Stroustrup - The real interview  (0) 2008.05.01
qsort vs sort  (0) 2008.05.01
RAII (Resource Acquisition Is Initialization)  (1) 2008.05.01
상속되지 않는것  (0) 2008.05.01
STL  (0) 2008.05.01

Resource Acquisition Is Initialization #

직역하면 자원의 획득은 초기화이다 ..

이말은 C++계의 대부 Bjarne Stroustrup 에 의해 나온 관용구 입니다.
http://www.research.att.com/~bs/homepage.html

자원(여기서 자원이란 메모리 뿐만 아니라 OS에 요청에서 얻어지는 모든건 ..)의
소멸(해제)은 Destructor(소멸자)에서 처리 하라는 말과 일맥 상통하는 말입니다.

자원의 획득은 생성자에서, 그 자원의 소멸은 소멸자에서 처리하여 어떠한 경우에도
자원의 leak이 발생하지 않게 처리하자 란 생각입니다.

만약 다음과 같은 코드가 쓰레드의 함수안에서 실행 되고 있을때 ...
CRITICAL_SECTION g_cs;
UINT Run(LPVOID)
{
  if (조건) {
    EnterCriticalSection(&g_cs); // 임계영역에 들어갑니다. 
    AFunction();
    BFunction();
    LeaveCriticalSection(&g_cs); // 임계영역에서 나옵니다. 
  }
  else {
    // 다른 작업 
  }
  return 0;
}
AFunction 함수에서 예외가 발생하여 Run함수를 빠져 나간다면 g_cs의 내용은
임계영역에서 못빠져 나온채 남아 있게 된니다.
그럼 나머지 쓰레드에서 실행되던 코드들은 EnterCriticalSection(&g_cs);
코드 앞에서 모두 대기하는 상태가 되어 프로그램이 DeadLock 상태에 빠지게 됩니다.

그러나 아래의 코드는 ...
class CriticalSection
{
public:
  CriticalSection(CRITICAL_SECTION *pcs) : pcs_(pcs)
  {
    EnterCriticalSection(pcs_);
  }

  ~CriticalSection()
  {
    LeaveCriticalSection(pcs_);
  };

private:
  CRITICAL_SECTION *pcs_;
};

CRITICAL_SECTION g_cs;
UINT Run(LPVOID)
{
  if (조건) {
    // 임계영역에 들어갑니다. 
        // 그리고 cs의 변수 생명이 끝날때 (if 문이 끝날때) 
        // 소멸자가 호출되 임계영역의 자원을 해제 해줍니다. 
    CriticalSection cs(&g_cs);

    AFunction();
    bool b = BFunction();
        if (!b) {
          return -1;
        }
  }
  else {
    다른 작업
  }
  return 0;
}

AFunction혹은 BFunction에서 예외가 발생하던 중간의 return문을
만나서 쓰레드 함수를 탈출한다고 해도 CriticalSection의 소멸자에서
임계영역의 자원을 풀어주므로 보다 안전한 코드를 만들수가 있습니다.

이개념이 RAII(Resource Acquisition Is Initialization) 입니다.

이 RAII 철학을 바탕으로 만들어진 C++ 표준 객체가 std::auto_ptr 입니다.
std::auto_ptr은 생성자에서 할당된 포인터를 받아 소멸자에서
delete 시키는 기능을 가진 포인터타입의 래퍼 객체 입니다.

std::auto_ptr은 다소 익숙하지 않은(일반포인터와 비교해)
소유정책을 가지고 있지만 호환성있는 표준 객체라는 점에서
눈여겨볼 아니 필요할때 꼭 사용되어져야 될 객체 입니다.

#include <iostream>
#include <memory>

void f()
{
  // string 객체를 동적으로 생성하고 명시적인 해제가 없지만 
  // std::auto_ptr의 소멸자에서 string 객체에 대한 할당된 포인터 객체를 
  // delete 해줄 것입니다. 
  std::auto_ptr<string> p(new string("메롱"));

  std::cout << *p << std::endl; // 포인터와 같은 인터페이스를 가집니다. 
  std::cout << p->lenght() << std::endl;
}

int main()
{
        f();
}


이밖에 RAII의 기본철학을 이용한 COW(copy on write)기법이나
Reference Counting 기법을 이용한 smart포인터등 보다 안전하고
융통성있는 객체의 코드를 만들수 있을 것입니다.


MS의 COM은 Reference Counting을 이용한 스마트 포인터로 핸들링 되며
_bstr_t 객체는 COW 타입을 사용해 성능 향상을 꾀한 예로 들수 있을 것입니다.

이밖에도 boost(표준라이브러리는 아니지만 앞으로 표준화의 가능성이 높은 성능좋은
라이브러리)의 smart_ptr 객체들도 auto_ptr의 확장 개념으로서 제공되고 있습니다.


'Dev > C++' 카테고리의 다른 글

qsort vs sort  (0) 2008.05.01
최소 완전한 클래스를 만들어라  (0) 2008.05.01
상속되지 않는것  (0) 2008.05.01
STL  (0) 2008.05.01
new 2  (0) 2008.05.01

상속되지 않는것 #
 
 constructor 
 destructor 
 assign operation 
 static member 
 friend 

'Dev > C++' 카테고리의 다른 글

최소 완전한 클래스를 만들어라  (0) 2008.05.01
RAII (Resource Acquisition Is Initialization)  (1) 2008.05.01
STL  (0) 2008.05.01
new 2  (0) 2008.05.01
new 1  (0) 2008.05.01

STL #

Standard Template Library

STL은 Alexander Stepanov가 Meng Lee와 함께 template으로
구현한 라이브러리 입니다.

1993년 표준화가 이루어질쯤 Alexander Stepanov의 STL을 보고
C++ 표준 위원회의 만장 일치에 의해서 표준에 합류 하게 되었고
STL로 인해 표준화는 몇년 늦어진 1998년에야 이루어 지게 됬습니다.
(이 기간 언어적인 확장은 없었으며 explicit 같은 제한적인 사항이
몇개 추가 되었습니다.)


STL은 공식적인 용어라기 보다 관용적으로 쓰는 C++의
라이브러리 입니다.

STL의 범위는 C++의 표준 라이브러리중 알고리즘과 Iterator를
사용하는 컨테이너 객체를 일반적으로 말합니다.


STL의 의의중 하나는 C++가 OOP언어만이 아닌
multi-paradigm programming language로서의 generic한 기능을
충분히 살린 라이브러리 한 점입니다.


generic programming이란 특정 데이터를 어떻게 가공하느냐의
OOP의 개념 촛점을 맞춘것이 아닌 알고리즘(구현) 부분에
촛점을 맞춘 프로그램밍 방법입니다.

#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <fstream>
using namespace std;

template <class IterT, class FuncT>
void ForEach(IterT B_, IterT E_, FuncT Fun_)
{
        while (B_ != E_) {
                Fun_(*B_++);
        }
}

void Print(char c)
{
        cout << c;
}


int main()
{
        char sz[] = "CHAR ARRAY";
        int nLen = strlen(sz);

        vector<char> v(sz, sz + nLen);

        ForEach(sz, sz + nLen, Print);
        cout << endl;

        ForEach(v.begin(), v.end(), Print);
        cout << endl;


        ifstream fin(__FILE__);
        ForEach(istreambuf_iterator<char>(fin),
                istreambuf_iterator<char>(),
                Print
        );

        cin.get();
}

ForEach는 std::for_each 함수를 흉내 내본 것입니다.

ForEach함수는 특정한 타입에 대해 구현을 해놓은것이 아니라
일반(generic)적인 타입에 대해서 순차적으로 노드를 이동해가며
Fun함수를 호출하는것입니다.

여기서 IterT는 char* 타입이든 특정 컨테이너의 Iterator 타입이든
후치증가연산자 "++" 와 operator*()를 제공되는 어떤 타입이라도
매치가 될수 있으며 FuncT 타입도 T(operator*()가 리턴하는 타입)
타입에 매칭되는 한개의 파라미터를 인수로 취하는 어떠한 함수도
매치가 될수 있습니다.


타입에 종속적이지 않는 일반적인 구현을 제공할수 있다는점이
generic programming의 핵심이며 그 generic programming 방식으로
만들어진 C++의 표준 라이브러리가 STL입니다.



STL의 구성 #


컨테이너 객체로는 아래와 같이 존재하며 algorithm 에는
70여개의 알고리즘 함수가 있고 그외 iterator(반복자)
그리고 유틸리티 함수로 구성 되어 있습니다.

컨테이너 
        deque 
        list 
        map 
        multimap 
        multiset 
        set 
        vector 

알고리즘 함수 
        adjacent_find               
        binary_search               
        copy 
        copy_backward               
        count                       
        count_if                     
        equal                       
        equal_range                 
        fill                         
        fill_n                       
        find                         
        find_end                     
        find_first_of               
        find_if                     
        for_each                     
        generate                     
        generate_n                   
        includes                     
        inplace_merge               
        iter_swap                   
        lexicographical_compare     
        lower_bound                 
        make_heap                   
        max                         
        max_element                 
        merge                       
        min                         
        min_element                 
        mismatch                     
        next_permutation             
        nth_element                 
        partial_sort                 
        partial_sort_copy           
        partition                   
        pop_heap                     
        prev_permutation             
        push_heap                   
        random_shuffle               
        remove                       
        remove_copy                 
        remove_copy_if               
        remove_if                   
        replace                     
        replace_copy                 
        replace_copy_if             
        replace_if                   
        reverse                     
        reverse_copy                 
        rotate                       
        rotate_copy                 
        search                       
        search_n                     
        set_difference               
        set_intersection             
        set_symmetric_difference     
        set_union                   
        sort                         
        sort_heap                   
        stable_partition             
        stable_sort                 
        swap                         
        swap_ranges                 
        transform                   
        unique                       
        unique_copy                 
        upper_bound                 


C++ Standard Library #

C++ Standard Library는 STL을 포함하며 그외에
iostream, complex, string 등등이 template 으로
작성 되어 있습니다.

표준 전의 C++ Standard Library는 모두 일반 클래스로
작성 되었으나 표준화 이후 모든 C++ Standard Library는
template으로 재작성 되었습니다.


그리고 새로운 헤더 형식이 채택 되었습니다.
// 예전 C++ 헤더 방식 입니다. 
// 일반 클래스로 작성된 라이브러리 이며 
// 더이상 표준은 아닙니다. 
// .h 가 붙은 헤더를 사용하시면 ISO C++의 호환성을 
// 보장할수 없습니다. 
// 일부 컴파일러는 옜날 코드를 위해 남겨 두었으나 
// 사용을 권장하지 않습니다. 
#include <iostream.h>



// 표준입니다. 
// template 으로 작성 되었으며 
// std 란 namespace 로 쌓여 있습니다. 
#include <iostream>


규칙은 이렇습니다.
C++ 표준 라이브러리는 .h 가 붙지 않습니다.
그리고 std 란 namespace 에 포함되어 있습니다.


C Standard Library #

C 언어는 C++의 부분 집합이며 라이브러리도 해당됩니다.
C 언어의 표준 라이브러리는 C++의 표준 라이브러리이기도 하며
C 언어의 헤더 형식을 사용 하면 됩니다.

#include <stdio.h>

그러나 C++ 의 header 규칙에 의하여 모든 C 라이브러리들은
앞에 c 가 붙고 .h 가 붙지않는 형식으로도 제공되며 권장되어 지고
그 형식으로 제공된 라이브러리는 std namespace에 포함 되어
있습니다.
#include <cstdio>   // #include <stdio.h> 
#include <cstring>  // #include <string.h> 
#include <cstdlib>  // #include <stdlib.h> 
#include <cmath>    // #include <math.h> 


C++ Headers #

<algorithm> <bitset> <cassert> <cctype> <cerrno> <cfloat> 
<ciso646> <climits> <clocale> <cmath> <complex> <csetjmp> 
<csignal> <cstdarg> <cstddef> <cstdio> <cstdlib> <cstring> 
<ctime> <cwchar> <cwctype> <deque> <exception> <fstream> 
<functional> <iomanip> <ios> <iosfwd> 
<iostream> <istream> <iterator> <limits> <list> <locale> 
<map> <memory> <new> <numeric> <ostream> <queue> 
<set> <sstream> <stack> <stdexcept> <streambuf> <string> 
<strstream> <utility> <valarray> <vector> <cstddef> <cstdlib> 
<exception> <limits> <new> <cstdarg> 

'Dev > C++' 카테고리의 다른 글

RAII (Resource Acquisition Is Initialization)  (1) 2008.05.01
상속되지 않는것  (0) 2008.05.01
new 2  (0) 2008.05.01
new 1  (0) 2008.05.01
initialization - array structure  (0) 2008.05.01

new의 실패 #

new 키워드의 메모리 할당은 operator new 함수에 의해 처리가 됩니다.

이 operator new 함수의 실패는 ISO C++표준 이전에는 NULL을 리턴하게 되었으나 ISO C++표준에서는 std::bad_alloc 객체를 예외로 발생 시키는 것으로 결정 되었습니다.

#include <stdexcept>
#include <iostream>
using namespace std;

int main()
{
        try {
                // 실패한다면 std::bad_alloc 예외 발생 
                int *p = new int[10000000];

                // 구식 컴파일러라면 이 조건에 .. 
                if (!p) {
                        cout << "bad alloc error : old version " << endl;
                        return -1;
                }
        }
       catch (std::bad_alloc &e) {
                cout << "bad alloc error " << endl;
        }
        catch (...) {
                cout << "unknown error " << endl;
        }
}
표준은 준수하는 컴파일러라면 exception(catch (std::bad_alloc &e))이 발생 할것이고 아니라면 if (!p) 조건에 해당되어 처리가 될것입니다.




예외없는 new #

위에서 언급했듯이 표준 이전의 스펙에서만 실패했을때 예외를 발생 시키지 않고 NULL을 리턴 하게 됩니다.

그러나 상황에 따라서는 실패시 NULL을 리턴하는 동작이 필요 할수도 있습니다.
혹은 예외의 비용이 부담되서, 혹은 예외가 지원되지 않아서 등등..

그래서 ISO C++ 표준에서는 예외를 발생시키지 않는 operator new 함수를 추가 했습니다.
void* operator new(std::size_t size, const std::nothrow_t&) throw();
void* operator new[](std::size_t size, const std::nothrow_t&) throw();
일반 operator new 함수에 2번째 인자 const std::nothrow_t& 가 추가가 된 형태 입니다.

#include <new>
#include <stdexcept>
#include <iostream>
using namespace std;

int main()
{
        try {
                int *p = new(nothrow) int[10000000];
                if (!p) {
                        cout << "bad alloc error : old version " << endl;
                        return -1;
                }
        }
        catch (std::bad_alloc &e) {
                cout << "bad alloc error " << endl;
        }
        catch (...) {
                cout << "unknown error " << endl;
        }
}
위의 코드에서는 예외를 발생 시키지 않고 실패시 NULL을 리턴하게 될것입니다.

'Dev > C++' 카테고리의 다른 글

상속되지 않는것  (0) 2008.05.01
STL  (0) 2008.05.01
new 1  (0) 2008.05.01
initialization - array structure  (0) 2008.05.01
operator overloading 2  (0) 2008.05.01

new #

new 키워드는 C++에서 힙영역에 메모리를 할당하기 위해 사용됩니다.

힙영역이란 프로그램(프로세스)이 메모리에 로딩이 될때 사용되는
메모리영역(정적영역, 스택, 코드영역) 을 제외하고 OS 차원에서
허용해주는 메모리 영역입니다.

그래서 힙영역은 프로그램차원에서 다룰수 있는 영역이 아니므로
OS에게 요청을해서 메모리를 받아와야 됩니다.

C언어의 malloc 함수와 C++의 new는 OS에게 그런 요청을 해서
메모리는 얻어오는 함수및 키워드 입니다.


new는 클래스 객체의 생성자를 호출해준다는 점에서
malloc 함수와는 차별화가 됩니다.

#include <iostream>
using namespace std;

class Item
{
public:
        Item() { cout << "ctor" << endl; }
        virtual ~Item() { cout << "dtor" << endl; }
};

int main()
{
        // Item 클래스의 메모리를 확보한후 
        // 생성자를 호출해 줍니다. 
        Item *p = new Item;
        Item *arr = new Item[10];

        // Item 클래스의 소멸자를 호출한후 
        // 메모리를 해제 합니다. 
        delete p;
        delete []arr; // new의 배열은 delete[] 로 해제합니다. 


        // Item 클래스의 메모리만 확보합니다. 
        // 생성자는 호출되지 않습니다. 
        Item *p2 = (Item *p)malloc(sizeof(Item));

        // Item 클래스의 메모리만 해제합니다. 
        // 소멸자는 호출되지 않습니다. 
        // 그것이 new로 생성된 객체일지라고 ... 
        free(p2);
}



operator new #


new의 기능은 크게 두가지로 나눕니다.

첫번째는 메모리를 항당하는 기능이고
두번째는 생성자를 호출하는 기능입니다.

이중 첫번째부분은 사용자에 의해 제어가 가능한 부분이지만
두번째 생성자를 호출하는 부분은 소멸자와 틀리게
컴파일러의 영역일뿐 사용자에 의해서 제어가 불가능한 부분입니다.

그럼 new의 메모리 할당은 어떻게 제어할까?
답은 operator new() 함수를 오버로딩 하는것입니다.


new의 메모리 할당은 내부적으로 컴파일러에 의해 수행 되는것이 아니고
메모리를 할당하는 operator new() 함수를 호출하여 메모리를 할당합니다.
그리고 그것에 대한 결과(할당된 메모리)에 해당 객체의 코드영역을 위치 시킨후
생성자를 호출합니다.

한마디로 컴파일러는 new의 동작에서 메모리 할당부분은
operator new 함수에게 위임 하게 되는것입니다.

그러므로 operator new를 오버로딩 한다면 메모리를 할당받는 과정을
사용자에 의해 변경 할수 있는 것입니다.


#include <iostream>
#include <string>
using namespace std;

class Custom
{
public:
        // 사용자정의 operator new 함수 
        void* operator new (size_t n)
        {
                return malloc(n);
        }

        // operator new를 정의 했다면 
        // 반드시 그에 상응하는 operator delete를 
        // 만들어 재앙을 막읍시다 
        void operator delete(void *p)
        {
                free(p);
        }

};

int main()
{
        Custom *p = new Custom();
        delete p;

}

위의 Custom 객체에 대한 new와 delete는
Custom::operator new() 와 Custom::operator delete()를
사용하게 됩니다.

placement new #


위에서 말했듯이 new의 생성자 호출은 사용자에 의해
제어가 불가능 합니다.
class Creator
{
public:
        Creator() {}
};

int main()
{
        Creator c;

        // 이걸 명시적으로 하고 싶은데 불행히도 
        // 이런것은 하지 못합니다. 
        // 에러 !! 
        c.Creator();        // 생성자호출 
}

그러나 또다른 new의 버전 placement new를 이용하면
비슷한 효과를 낼수도 있습니다.


placement new의 기본적인 내용은 메모리 할당은 직접 안하고
할당된 메모리에 객체를 생성 시키는 일만 합니다.

#include <iostream>
#include <string>
using namespace std;


int main()
{
        // 메모리 할당만 합니다. 
        // 생성자 호출은 안합니다. 
        string *pHeap = (string*)malloc(sizeof(string));
        // C++식 단순 메모리 할당 입니다. 
        // malloc과 같은 내용입니다.   
        // string *pHeap = (string*)operator new (sizeof(string)); 


        // 정적으로 메모리를 잡습니다. 
        // 당연히 스택에 메모리가 잡히겠죠   
        char pStack[sizeof(string)];

        // 메모리 생성은 안하고 
        // 생성된 메모리 pBuff에 string을 코드를 
        // 올려 놓고 생성자를 호출합니다. 
        new (pHeap) string("할당된메모리에 생성");

        // 스택에 string 객체를 생성합니다. 
        new (pStack) string("정적메모리에 생성");


        // 소멸자를 명시적으로 호출해 줍니다. 
        // 미리 할당된(정적이든 동적이든) 메모리에 
        // 객체만 생성하는것이기 때문에 
        // pHeap이 메모리가 해제 된다고 해도 string의 
        // 소멸자가 자동으로 호출되지 않습니다. 
        // 그러므로 소멸자를 호출 안하거나 
        // 두번이상 소멸자를 호출하는 재앙은 
        // 사용자의 책임입니다.   
        pHeap->~string();

        // 소멸자 호출   
        // pStack은 char타입의 배열이므로 
        // string* 형으로 명시적인 형변화 필요   
        reinterpret_cast<string *>(pStack)->~string();

        // pHeap의 메모리를 해제 합니다. 
        // operator new로 할당 했다면 
        // operator delete(pHeap) 
        free(pHeap);

        // pStack은 stack에 할당 되었으므로 
        // 해제가 필요없습니다. 
        // 이 함수가 끝나면 자동으로 스택에서 
        // 제거 됩니다.   

}

placement new는 메모리 할당의 제약이 있는 임베디드시스템이나
혹은 다른 프로그램 기법상 필요한
(예를들어 기본생성자가 없는 객체의 배열생성이나 메모리 풀링 등등)
일을 할때에 유용하게 사용할수 있을 것입니다.


참고: More Effective C++

'Dev > C++' 카테고리의 다른 글

STL  (0) 2008.05.01
new 2  (0) 2008.05.01
initialization - array structure  (0) 2008.05.01
operator overloading 2  (0) 2008.05.01
operator overloading 1  (0) 2008.05.01

배열및 구조체의 초기화 #

// 3개의 원소를 각각 1, 2, 3 으로 초기화 
int nArr[3] = { 1, 2, 3 };

// 4개의 원소를 가지는 배열 4개를 1, 2, 3, 4 로 초기화 
// 이때 배열의 개수는 4개로 자동으로 정의됨 
int nArr[] = { 1, 2, 3, 4 };

struct St {
  int a;
  int b;
};

// 구조체 St의 멤머 a, b를 각각 1, 2로 초기화 
St st = { 1, 2 };

// 구조체의 배열 초기화 
St st[2] = { { 0, 1 }, { 2, 3 } };


초기화 되지 않은 auto 변수는 정의되지 않은 값을 가진다 #

// 어떤값이 들어있는지 정의되지 않았음 
int nArr[3];
St st;
St st[2] ;

// 물론 배열및 구조체 변수가 아닌 일반 auto 변수도 같이 적용 
int n; // 정의되지 않음 


부분초기화된 배열및 구조체 #

부분 초기화된 배열및 구조체의 나머지 원소나 멤버의 값은 static변수처럼(0으로 초기화) 된다

// 첫번째 원소에 0을 초기화 하고 나머지 2개의 원소에는 0을 적용 
int nArr[3] = { 0 };

// 첫번째와 두번째에 각각 1, 3으로 값을 초기화 하고 나머지 3개의 원소에 대해서는 0으로 초기화 한다 
int nArr[5] = { 1, 3, };

// 맨 마지막 콤마는 생략 가능 
int nArr[5] = { 1, 3 };


struct St {
  int a;
  int b;
};

// St의 a의 멤버에 2를 초기화 하고 나머지멤버인 b에 0을 초기화 
St st = { 2 };
St st = { 2, };


모든원소에 0으로 초기화 #

struct St {
  int a;
  int b;
};

// 0으로 초기화 하는 같은 내용들   
St st = { 0, 0 };
St st = { 0, };
St st = { 0 };
St st = {};

int nArr[5] = { 0, 0, 0, 0, 0 };
int nArr[5] = { 0, };
int nArr[5] = { 0 };
int nArr[5] = {};

'Dev > C++' 카테고리의 다른 글

new 2  (0) 2008.05.01
new 1  (0) 2008.05.01
operator overloading 2  (0) 2008.05.01
operator overloading 1  (0) 2008.05.01
Conversion Functions - 변환함수  (0) 2008.05.01

+ Recent posts