7.30(월) C++ - Small Object Allocator

from Study/C++ 2007/07/31 16:47 view 29394

#include <iostream>

using namespace std;

 

// Small Object Allocator

// More Effective C++ 항목8

// Modern C++ design 4- 작은 객체의 메모리 할당기 만들기

// 미리 메모리를 크게 잡아놓고(리스트) new/delete를 해준다.
// 메모리 할당과 소멸시간을 줄여준다.
// 메모리를 사용하지 않으면 하드디스크에 페이지 형태로 잡아놓기 때문에
// 메모리의 낭비를 걱정 하지 않아도 된다??
 

class Point

{

        int x;

 

        union

        {

               int y;

               Point* next;

        };

        static Point* FreeList;

 

public:

        Point( int a = 0, int b = 0 ) : x(a), y(b) {}

 

        void* operator new( size_t sz )

        {

               if( sz != sizeof(Point) )      // Point 객체 할당이 아니라면

                       return ::operator new( sz );  // 전역new를 사용하게 한다.

               if( FreeList == 0 )           // 최초 실행되는 경우

               {

                       // 전역operator new를 사용해서500개를 사용하자.

                       FreeList = (Point*)::operator new(sizeof(Point)*500);

 

                       // single linked list로 연결한다.

                       for( int i = 0; i < 499; ++i )

                              FreeList[i].next = &FreeList[i+1];

               }

               // 1번째 노드를 떼어서 리턴해 준다.

               Point* temp = FreeList;

               FreeList = FreeList->next;

 

               return temp;

        }

        // delete 시에도 아래함수가 호출된다.

        // delete는 오버로딩이 되지 않는다.
        //
, 멤버일때 아래 모양만 허용된다. 자기를 delete를 방지??

        void operator delete( void* p, size_t sz )

        {

               if ( p == 0 ) return;         //NULL 포인터인지를 확인해줘야 한다.

 

               if( sz != sizeof(Point) )

               {

                       ::operator delete(p);

                       return;

               }

 

               // List의 제일 앞부분에 놓는다.

                Point* temp = (Point*)p;

               temp->next = FreeList;

               FreeList = temp;

        }      

};

 

Point* Point::FreeList = 0;

 

 

void main()

{

        Point* p1 = new Point( 1, 1 );

        Point* p2 = new Point( 2, 2 );

        Point* p3 = new Point( 3, 3 );

 

        cout << p2 << endl;

        delete p2;

 

        Point* p4 = new Point(0, 0);

 

        cout << p4 << endl;    // p4 와 같은주소는 p1, p2, p3중 어느것 일까요?

 

        delete p1;

        delete p3;

 

        Point* p5 = 0;

        delete p5;                    //NULL 포인터도 delete 가능하다.

}

 

Tag |

7.30(월) C++ - 상속과 포함

from Study/C++ 2007/07/31 15:14 view 30663

// 상속과 static

class Parent

{

public:

        static int x;

};

 

int Parent::x = 0;

 

class Child : public Parent

{

};

 

void main()

{

        Parent::x = 10;

        Child::x  = 20; //될까??

 

        cout << Parent::x << endl; // 얼마?? 20 부모자식이모두공유.!!

}

 

// 상속과생성자

class Parent

{

public:

        Parent() {}      // 1

        Parent(int a) {} // 2

};

 

class Child : public Parent

{

public:

// 3 컴파일러가 Parent()를 자동으로 생성해서 부모디폴트를 호출한다.
       
Child() : Parent() {} 

        Child(int a) : Parent(a) {} // 4

};

 

void main()

{

        Child c(1);    // 1- 4 주의부모는항상default 생성자호출

}

 
 

// protected 생성자의미: 자신을만들수없지만자식은만들수있다.!!!!

class Animal

{

protected:

        Animal() {}

};

 

class Dog : public Animal

{

public:

        Dog() {}

};

 

void main()

{

        Animal a;

   // protected로 감싸주면 현실세계를 반영 할 수 있다. 동물은 만들지 못하지만 개는 만든다.
       
Dog    d;
}

 

 

// 접근변경자- 언제사용하는가? 자주나오지는않지만알아둘필요가있다.

class Parent

{

private:       int a;

protected:     int b;

public:        int c;

};

 

class Child : public Parent

{

        int a;  // 메모리에있지만접근불가.

        int b;

        int c;

};

 

 

// STLlinked list가 있다. - 그런데 stack이 없다고 가정

// Adapter Design Pattern : 임의의클래스의interface(함수이름)을변경해서

//                         다른클래스처럼보이게하는기법.

// private 상속: 구현을물려받지만interface는물려받지않겠다.

 

#include <list>

 

// 부모의 가상함수를 재정의 해 주고 싶을 때에는 상속을 통하여 한다.

class Stack : private list<int>

{

public:

    // 부모인list를재사용한다.

        void Push( int a )     { push_back(a);  }
       
void Pop()             { pop_back();  }      // 제거만한다.

        int  top()             { return back(); }   // 리턴만한다.

};

 

void main()

{

        Stack s;

        s.Push(10);

 

   // s.push_front(10);
   //
이 순간 Stack은 망가지게 된다. private 상속을 통해 막아버리자.

}

// 하지만  상속보다는 포함을 사용한 Adapter가 훨씬 좋은 기법이다.

class Stack

{

        list<int> st;

public:

        void Push( int a ) { st.push_back(a); }

};

 

Tag |

7.30(월) C++ - 함수객체, 주소연산자

from Study/C++ 2007/07/31 15:08 view 31386

#include <iostream>

using namespace std;

 

// 함수객체

// ()연산자를 재정의해서 함수처럼 동작하는 객체.

// 상태를 가지는 함수-> 함수 보다 훨씬 뛰어나다.

// 암시적인 inline을 갖는다.

// 함수보다 빠를 때가 있다. 일반 함수가 인자로 전달될 때 함수 포인터를 사용한다.
// (inline
을쓰지못한다.pointer이기 때문에.)

 

// 아래와 같은 경우는 지속적인 값을 가지지못한다. 매번값을넘겨줘야한다.

int plus( int a, int b, int ba )

{

        static int base = 0;

        base = ba;

        return a + b + base;

}

/////////////////////////////////////////////////////////////

 

class plus

{

        int base;

public:

        plus( int a = 0 ) : base(a) {}

 

        int operator()(int a, int b)

        {

               return a + b + base;

        }

};

 

void main()

{

        plus p(10);

 

        int s = p( 1, 2 );     // p.operator()(1,2)

 

        cout << s << endl;

}

 

// 컴파일러가만들어주는것들

 class Point

{

        int x, y;

 

public:

        void* operator&()

        {

               return this;

        }

 

        const void* operator&() const

        {

               return this;

        }

};

 

 

void main()

{

        const Point p;

 

        cout << &p << endl;;
        // p.operator&()
주소연산자도재정의가능하지만안하니못하다.!!

}

 

Tag |

7.30(월) C++ - finding memory leak

from Study/C++ 2007/07/31 14:32 view 1792755

// memory.cpp
#include
"memchk.h"

 

// finding memory leak

int main()

{

        int* p1 = new int;

        int* p2 = new int;

        int* p3 = new int;

 

        delete p2;

 

//      cout << __FILE__ << endl;     // 컴파일 하는 파일이름

//      cout << __LINE__ << endl;     // 컴파일 하는 LINE NO

 

        return 0;

}

 

//memchk.h

#include <iostream>

using std::cout;

using std::endl;       // .h 에서는 절대로 namespace를 통째로 열지마라!!(격언중하나)

 

#ifdef _DEBUG

 

struct MemInfo

{

        char name[256];        // 화일이름

        int  line;             // new를호출한line no

        void* addr;            // 할당한메모리주소

};

 

MemInfo mem[10000];  // 최대10000개의 메모리 할당을기록( linked list를 사용해도 됨 )

int count = 0;

 

void* operator new( size_t s, char* file, int line )

{

        void* p = malloc( s );

 

        // 배열에 할당정보를 기록한다.

        mem[count].addr = p;

        mem[count].line = line;

        strcpy( mem[count].name, file );

 

        ++count;

 

        return p;

}

 

void operator delete( void* p )

{

        for( int i = 0; i < count; i++ )

        {

               if( mem[i].addr == p )

               {

                       mem[i] = mem[count-1]; // i번째를 제거

                       --count;

                       break;

               }

        }

        // 배열에 없는 정보라면 에러처리를 하는 것도 좋은방법.

        free(p);

}

 

int MAIN();

 

void main()

{

        MAIN();

 

        if ( count == 0 )

        {

               cout << "NO Memory Leak" << endl;

               return;

        }

 

        cout << "Found " << count << " Memory Leak" << endl;

 

        for( int i = 0; i < count; ++i )

        {

               cout << "FILE : " << mem[i].name << endl;

               cout << "FILE : " << mem[i].addr << endl;

               cout << "FILE : " << mem[i].line << endl;

               cout << endl;

        }

}

 

 

// 꼭 외워 두세요. new에 인자를 더 보내주기 위한 좋은 방법

#define new new(__FILE__, __LINE__)

#define main MAIN

 

// C에 적용해보고 싶을때!!

#define malloc(x)      MyMAlloc( x, __FILE__, __LINE__ )

#define free(x)               MyFree(x)

 

#endif // _DEBUG

Tag | ,

7.30(월) C++ - new/delete 총정리

from Study/C++ 2007/07/31 13:07 view 29133

// 1. new의 동작방식  (A) operator new() 호출해서 메모리 할당.
//                 (B) A가 성공하면 생성자 호출.

 

class Test

{

public:

        Test()  { cout << "Test()" << endl; }

        ~Test() { cout << "~Test()" << endl; }

};

 

void main()

{

        Test* p = (Test*)operator new( sizeof(Test) );

        operator delete( p );

        //Test* p = new Test;

        //delete p;

}

 

// 2. operator new() 를재정의할수있다.

// 3. Array New

// 4. Member New

class Point

{

public:

        void* operator new( size_t s )

        {

               return malloc( s );

        }

};

 

Point* p = new Point;
 

void* operator new( size_t sz )

{

        cout << "operator new" << endl;

 

        return malloc( sz );

}

 

// Array New

void* operator new[]( size_t sz )

{

        cout << "operator new[]" << endl;

        return malloc( sz );

}

 

void main()

{

        int* p = new int;

        delete p;

 

        int* p2 = new int[10]; // Array new 호출 -> 없다면

        delete[] p2;

}

// 5. overloading new

// 다음 함수는 왜 만들었을까요? 메모리부터 잡고 객체를 생성하는 기법.

class Test

{

public:

        Test() { cout << "Test()" << endl; }

};

/* 전달된객체를반환해준다!!!

void* operator new( size_t s, void* p )

{

        return p;

}

*/

void main()

{

        Test* p = new Test; // operator new( size_t )로메모리할당후생성자호출

 

        // 객체를메모리에먼저잡고생성자를호출하는기법MapView( ?? )

        // 메모리는Cmalloc 의잡고나서객체를집어넣는다.

        new(p) Test;      // p를이미생성된메모리에반환!!

                          // operator new( size_t, void* ) 호출후생성자호출.

}


////////////////////////////////////////////////////////////////////////
// 6. nothorw
의 동작 방식!!!

// new : 실패시 예외전달( std::bad_alloc )

// new(nothrow) : 실패시 0


void
* operator new( size_t s )

{

        // 실패시예외발생

}

 

// 코드를설명적으로만들수있다.

class nothrow_t   // empty class - sizeof(nothrow_t) => 1

                  // overloading 함수를만들때사용할수있다. 설명적인코드가된다.

{

};

nothrow_t nothrow;

 

void* operator new( size_t s, nothrow_t )

{

        // 실패시0을리턴

}

 

// new의 새로운 방식

#define new new(nothrow)    // 예전코드의호환을위해서define 해준다.

void main()

{ 

        // VC2005 등의최신컴파일러는모두new 가실패시예외가나온다.

        int *p = 0;

        try

        {

               p = new int[1000];

               *p = 10;

               delete[] p;

        }

        catch( std::bad_alloc e )

        {

               cout << "메모리할당실패" << endl;

        }

///////////////////////////////////////////////////////////////

        int* p = new int[];

        if ( p == 0 )

        {

               cout << "메모리를할당할수없습니다." << endl;

        }

        else

        {

               *p = 10;       // 메모리사용

               delete[] p;

        }

}


/////////////////////////////////////////////////////////////////////
void
* operator new( size_t s )               // 1

{

        return malloc( s );

}

 

void* operator new( size_t s, char* p )      // 2

{

        cout << "new : " << p << endl;

        return malloc( s );

}

 

void main()

{

        int* p = new int;

 

        int* p2 = new ("AAA") int;

 

        delete p;

}

 

 

 

 

Tag |