괴짜 프로그래머의 일상사~@@
프로그래밍, 컴퓨터, 그리고 일상에 관한 소소한 이야기들...
Blog | Guestbook
Keyword | Local | Tag
T 137 / Y 700 / Total 3405195
Catergories
Calendar
«   2023/06   »
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30  
Tag
PVOID, 러브홀릭, 지도 밖으로 행군하라, 서른 즈음에, 결승, 헥사 에디터, vim 7.1, 증가, 하나로 통신, 부스걸, 사건, 빌게이츠, 웹서비스, 할아버지, pdf, 설경구, 기부, 루이 로페즈, 그룹명, DDK,
Archive
Link
Search
  submit
Recent Articles
Recent Comments
Recent Trackbacks
2007/08/01 16:41
배열 범위 체크
[GGG]
C/C++언어는 기본적으로 배열에 대해서 범위 체크를 하지 않습니다. 여러가지 이유가 있겠지만 주된 이유는 속도 때문일 겁니다. 아무래도 첨자 검사를 위해서는 추가적인 코드가 들어가야 할테니까요. 그런데 이런 속도 상의 손해를 감수하고도 꼭 반드시 배열 범위를 검사해야 하는 경우가 있습니다. 바로 외부 데이터를 읽어 들이는 과정입니다. 메모리 상에서 내부적으로 조작하는 데이터야 버그와 해킹이 아닌 이상 신뢰할 수 있는 값을 항상 제공하겠지만, 외부의 파일이나, 네트워크 스트림의 내용은 언제든지 위, 변조될 가능성이 있습니다. 오류로 잘못 읽어지는 경우도 있겠죠. 따라서 이러한 곳에는 반드시 범위 검사를 넣어야 합니다. 그래야 안전하죠.

배열이 한, 두개인 경우야 수동으로 범위검사를 할 수 있겠지만, 세 개만 넘어가도 더 이상 수동으로 하기 힘들어 집니다. 또한 오류 발생 가능성도 높죠. 이러한 경우에 사용할 수 있는 간단한 템플릿 클래스가 아래 나와있습니다. 이 클래스는 배열과 호환되는 클래스로 내부적으로 크기 정보를 가지고 범위 검사를 수행합니다. 범위를 벗어나면 EOutOfRange 예외를 던집니다. T에는 배열을 저장할 타입을, size에는 해당 배열 크기를 집어넣으면 됩니다.
[CPP]template <typename T, size_t size>
class CFixedArray
{
private:
    T m_data[size];
    const size_t m_size;

    CFixedArray(const CFixedArray &);
    CFixedArray &operator =(const CFixedArray &);

public:
    CFixedArray() : m_size(size) {}

    T &operator [](int index)
    {
        if(index < 0 || index > size)
            throw EOutOfRange(_T("CFixedArray: 범위 초과"));

        return m_data[index];
    }

    operator T *() { return m_data; }
    size_t Size() const { return m_size; }
};[/CPP]아래는 예외 클래스와 CFixedArray를 사용하는 샘플 코드 입니다.
[CPP]class Exception
{
private:
    const TCHAR *m_msg;

public:
    Exception(const TCHAR *msg) : m_msg(msg) {}
    Exception(const Exception &r) { m_msg = r.Msg(); }

    Exception &operator =(const Exception &r)
    {
        if(this != &r)
            m_msg = r.Msg();

        return *this;
    }

    const TCHAR *Msg() const { return m_msg; }
};

class EOutOfRange : public Exception
{
public:
    EOutOfRange(const TCHAR *const msg) : Exception(msg) {}
};

int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        CFixedArray<CFixedArray<int, 30>, 30> a;
        CFixedArray<CFixedArray<int, 30>, 30> b;

        a[3][5] = 4;
        printf("%d\n", a[3][5]);
    }
    catch(Exception &ex)
    {
        printf("%S\n", ex.Msg());
    }

    return 0;
}[/CPP]요즘 프로그램에서 기초적인 형태의 배열을 사용하는 경우는 거의 없습니다. 대부분 벡터나 잘 포장된 형태의 가변 길이 배열을 지원하는 켄테이너 클래스를 사용하죠. 프로그램의 버그를 줄이고 싶다면 이러한 형태의 컨테이너 클래스를 사용하는 것이 좋은 습관입니다. 결론은 별로 그닥 유용한 코드는 아니라는 것이죠. ㅋㅋㅋㅋ


Trackback : http://jiniya.net/tt/trackback/551
TohnoLyn (2007/08/01 16:53)
유용하진 않을지몰라도 ^^;

재미잇는 코드네요 잘보고갑니다.
codewiz (2007/08/03 15:27)
네.
볼건 없지만 자주 놀러와 주세요 ^^

풀리비 (2007/08/07 00:47)
안녕하세요. 종종 들어와 좋은 글 보고 갑니다.
코드위즈님께서 마지막에 강조하신 것과 제 생각은 다릅니다. 컨테이너 클래스를 유용하게 사용하면 좋지만, 그것의 한계를 알고, 상황에 따라 적절히 사용할 수 있어야 합니다.
게다가 vector와 같은 자료구조도 [] 연산자를 사용해 원소를 접근한다면 일반 배열에서 []연산자로 원소 참조하는 것과 다를 바 없이 위험합니다. 단지 더 안전한(예외를 던지는) at() 멤버 함수를 더 구비하였고, iterator로 원소를 접근하라고 권고할 뿐이지요. 이는 성능과 안전 사이의 선택에 대한 책임을 개발자에게 남긴 것입니다.
가변 길이라 어쩔 수 없는 overhead를 가지는 vector를 극복하고자 하는 고민의 결과 중 하나가 boost::array (코드위즈님의 CFixedArray와 같은 목적, 다른 계기)라이브러리입니다. vector랑 다 같은데 고정크기 배열이라는 것만 다릅니다. 그래서 많은 STL 알고리즘에서 사용할 수 없지요... merge() 등..
codewiz (2007/08/07 12:35)
좋은 의견 감사합니다.
저도 전적으로 풀리비님 말씀에 동의합니다.

일반적인 상황에서는 대체적으로 가공되지 않은 배열보다는 컨테이너 객체를 사용하는 것이 좋은 선택입니다. 여러가지 이유가 있겠지만 제가 생각하는 두 가지 이유는 보통의 문제가 극도로 타임 크리티컬 하지 않다는 점과, 사람의 시간이 기계의 시간보다는 더 비싸다는 점입니다.

물론 컨테이너를 사용함에 있어서는 풀리비님 말씀대로 각 컨테이너의 장단점을 살려서 사용해야 함은 두말할 필요도 없이 중요한 내용입니다.


Name   Password   Home   Secret   Submit
 Prev   1  ...  164   165   166   167   168   169   170   171   172  ...  604   Next 
codewiz’s Blog is powered by Tattertools.com / Designed by faido