7.30(월) C++ - finding memory leak

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

// 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 25432

// 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 |

7.27(금) C++ - iterator 의 구현

from Study/C++ 2007/07/30 14:48 view 40592

#include <iostream>

using namespace std;

 

template<typename T> class slist

{

        struct Node

        {

               T         data;

               Node* next;

               Node( T d, Node* n ) : data(d), next(n) {}

        };

        Node* head;

public:

        slist() : head(0)      {}

 

        void push_front( T a ) { head = new Node( a, head ); }

 

        // list의각요소를접근하기위해스마트포인터를넣는다.

        // 내포로만들거나외부에(그리고내부에typedef로선언) 만들수있다.

        class iterator

        {

               Node* current;

        public:

               typedef T value_type;

               iterator( Node* init = 0 ) : current( init ) {}

 

               iterator& operator++()

               {

                       current = current->next;

                       return *this;

               }

               T& operator* ()

               {

                       return current->data;

               }

               bool operator !=( const iterator& i )

               {

                       return (current != i.current);

               }

        };

        //-------------------------------------------------------

        // 이제slist의처음과past the end iterator를리턴하는함수를제공한다.

        iterator begin() { return iterator(head); }

        iterator end() { return iterator( 0 ); }

};

/*

// 주어진구간의합을출력하는알고리즘을만들고싶다.

 

// 컴파일러에의한타입추론(type ??), 타입을알지못하므로컴파일러에게맡긴다??

// 단점: 리턴값을갖지못한다. 타입을모르므로?? void!!

template<typename T, typename T2> void sum_imp( T first, T last, T2 init )

{

        T2 s = init;

 

        while ( ++first != last )

        {

               s = s + *first;

        }

        cout << s << endl;

}

template<typename T> void sum( T first, T last )

{

        sum_imp( first, last, *first );

}

*/

 

// 버전2. 주어진구간의합을리턴하는함수를만들어보자.

// 모든반복자는자신과연관된typetypedef로가지고있다.( value_type으로꺼내면된다. )

 

// 간접층을만들어type문제를해결한다. (int, int), 반복자특성클래스.

template<typename T> struct xiterator_traits

{

        typedef typename T::value_type value_type;

};

 

// template 부분전문화( 포인터로되어있는것)

template<typename T> struct xiterator_traits<T*>

{

        typedef T value_type;

};

 

template<typename T>
typename xiterator_traits<T>::value_type sum( T first, T last )

{

        //typename T::value_type s = *first;
        //
어떠한타입이올지모르므로0을대입해서는안된다.

 

        typename xiterator_traits<T>::value_type s = *first;

 

        while ( ++first != last )

        {

               s = s + *first;

        }

        return s;

}

 

void main()

{

        int x[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        int n2 = sum( x, x+10 );

 

        slist<int> s;

 

        s.push_front( 10 );

        s.push_front( 20 );

        s.push_front( 30 );

        s.push_front( 40 );

 

        //slist안에있는모든요소의합을구하고싶다.

        int k = sum( s.begin(), s.end() );

 

        cout << k << endl;

}


////////////////////////////////////////////////////////////////////
// iterator_category 의 구현
template<typename T> struct xiterator_traits

{

        typedef typename T::value_type value_type;

        typedef typename T::iterator_category iterator_category;

};

 

// template 부분전문화( 포인터로되어있는것)

template<typename T> struct xiterator_traits<T*>

{

        typedef T value_type;

        typedef random_access_iterator_tag   iterator_category;

};

 

//임의접근일경우

template<typename T> void xadvance(T& p, int n ,random_access_iterator_tag)

{

        p += n;

}

 

template<typename T>

void xadvance( T& p, int n )

{

        xadvance( p, n, xiterator_traits<T>::iterator_category() );

}

 

void main()

{

        int x[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

 

        int *p = x;

 

        xadvance( p, 3 );   // p의반복자를3만큼전진해야한다. p+n 처리를하자.

 

        cout << *p << endl;    // 4이나와야한다.

}

Tag |

7.27(금) C++ - 일반적인 선형검색

from Study/C++ 2007/07/30 14:36 view 27261

#include <iostream>

using namespace std;

 

// 일반적프로그램의개념

// 선형검색: 주어진구간에서주어진조건을만족하는값을찾는다.

 

// 구간의조건: NULL 로끝나는문자열

// 구간의이동: ++

// 실패의경우: 0을리턴

// 단점: 반드시NULL을끝나는문자열이어야한다. - 너무특수한상황이다.

/*

char* xstrchr( char* s, int c )

{

        while( *s != 0 && *s != c )

               ++s;

 

        return *s == c ? s : (char*)0;

}

*/

 

// 보다일반화한버전.

// 주어진구간의조건: [begin , end) - 반개행구간. 한쪽만열려있다는의미>> [ ~ )

// 이때endpast the end 라고한다.

// 구간의이동: ++

// 실패의처리: past the end

// 장점: 부분문자열검색이가능하다-> 보다일반화되었다.

// 단점: 문자열(char)만검색가능하다. -> template으로일반화하자.

/*

char* xstrchr( char* begin, char* end, int c )

{

        while( begin != end && *begin != c )

               ++begin;

 

        return begin;

}

void main()

{

        char s[10] = "ABCDEFG";

        //char* c = xstrchr( s, 'C' );

        char *c = xstrchr( s, s+4, 'C' );

 

        if ( c == s + 4 )

        {

               cout << "실패" << endl;

        }

        else

               cout << *c << endl;

}

*/

 

// 버전3. template의도입

// 모든type의배열로부터선형검색을수행한다.!!

/*

template<typename T1, typename T2> T1 find( T1 first, T1 last, T2 value )

{

        while( first != last && *first != value )

               ++first;

 

        return first;

}

 

void main()

{

        int x[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

 

        int* p = find( x, x+10, 3 );

 

        if( p == x+10 )

        {

               cout << "값을찾을수없습니다." << endl;

        }

        else

               cout << *p << endl;

}

*/

 

// 이제Single Linked List를고려해보자.

template<typename T> class slist

{

        struct Node

        {

               T         data;

               Node* next;

               Node( T d, Node* n ) : data(d), next(n) {}

        };

        Node* head;

public:

        slist() : head(0)      {}

 

        void push_front( T a ) { head = new Node( a, head ); }

 

        // list의각요소를접근하기위해스마트포인터를넣는다.

        // 내포로만들거나외부에(그리고내부에typedef로선언) 만들수있다.

        class iterator

        {

               Node* current;

        public:

               iterator( Node* init = 0 ) : current( init ) {}

 

               iterator& operator++()

               {

                       current = current->next;

                       return *this;

               }

               T& operator* ()

               {

                       return current->data;

               }

               bool operator !=( const iterator& i )

               {

                       return (current != i.current);

               }

        };

        //-------------------------------------------------------

        // 이제slist의처음과past the end iterator를리턴하는함수를제공한다.

        iterator begin() { return iterator(head); }

        iterator end() { return iterator( 0 ); }

};

 

// 모든type의모든자료구조로부터선형검색을수행한다.!!

template<typename T1, typename T2> T1 find( T1 first, T1 last, T2 value )

{

        while( first != last && *first != value )

               ++first;

 

        return first;

}

 

// 모든type의모든자료구조로부터선형검색을수행한다.!!

// 상수가아닌조건을만족하는것을찾는다.주어진조건을찾는다!!!

template<typename T1, typename T2> T1 find_if( T1 first, T1 last, T2 pred )

{

        while( first != last )

        {

               if ( pred(*first) )

                       break;

               ++first;

        }

 

        return first;

}

bool foo( int a )

{

        return a % 3 == 0;

}

 

void main()

{

        int x[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

 

        int* p2 = find_if( x, x+10, foo );

 

        cout << *p2 << endl;

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

        slist<int> s;

 

        s.push_front(10);

        s.push_front(20);

        s.push_front(30);

        s.push_front(40);

 

        slist<int>::iterator p = find( s.begin(), s.end(), 20 );

 

        cout << *p << endl;

        ++p;

        cout << *p << endl;

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

        p = find_if( s.begin(), s.end(), foo );

        cout << *p << endl;

}

 

Tag |

7.27(금) C++ - 스마트포인터

from Study/C++ 2007/07/30 14:34 view 25069

#include <iostream>

using namespace std;

 

// 1) 개념: -> 연산자를재정의해서다른객체의포인터역할을하는객체.

// 2) 원리: -> 연산자재정의

// 3) 장점: 자원관리를자동으로할수있다.

// 4) explicit 생성자SPTR<int> p2( new int ); 로생성해야한다.

// 5) Owner Ship 관리- 중요!

 

class Test

{

public:

        int x;

        void foo() { cout << "Test::foo" << endl; }

};

 

template<typename T> class SPTR

{

        T* _obj;

        int* pCount;   // 참조카운팅을하기위해

 

public:

        explicit SPTR( T* p ) : _obj(p)

        {

               pCount = new int(1);          // 힙에카운팅을만든다.!!

        }

 

        ~SPTR()

        {

               if( --(*pCount) == 0 )

               {

                       delete _obj;

                       delete pCount;

               }

        }              // 자동삭제가능.

 

        T* operator->() { return _obj; }

        T& operator *() { return *_obj; }

 

        // 참조개수기법으로구현한복사생성자

        SPTR( const SPTR& s )

        {

               _obj = s._obj;

               pCount = s.pCount;

               ++(*pCount);

        }

 

        /*

        // 소유권이전

        SPTR( SPTR<T>& s )

        {

               _obj = s._obj;

               s.obj = 0;

        }

        */

};

 

void main()

{

        SPTR<Test> p1( new Test );

       

        SPTR<Test> p2 = p1;

}

 

/* 1) ~ 4)

void main()

{

        //SPTR<int> p2 = new int;             // explicit 생성자라서error

       

        SPTR<int> p2( new int );

        *p2 = 20;

        cout << *p2 << endl;

 

        //Test* p = new Test;

        //SPTR<Test> p = new Test;    // SPTR P( new Test );

        SPTR<Test> p( new Test );     // SPTR p( new Test );

 

        (*p).x = 10;

 

        cout << (*p).x << endl;

 

        p->foo();                     // (p.operator->())foo() 이지만

                                             // 컴파일러가(p.operator->())->foo()로해석해준다.

}

*/

 

 

/*      스마트포인터에장점!!

void ReleaseFucntion( FILE * f)

{

        fclose(f);

}

 

void foo()

{

        //int* p = new int;

        SPTR<int> p( new int );       // Resource Acqusion Is Initialize (RAII)

        {

               //fclose 를대신할ReleaseFucntion !!

               //생성자에서함수포인터를받아서delete할때ReleaseFucntion 호출

               //SPTR<FILE> p2( fopen( "a.txt", "wt" ), ReleaseFucntion );

               SPTR<FILE> p2( fopen( "a.txt", "wt" ), fclose );

        }

 

        if ( n == 0 )

        {

               //delete p;

               return;

        }

 

        //delete p;

}

*/


Tag |

// explicit 없이 암시적인 변환을 막는다.(간접층 사용! proxy)

class Stack

{

        struct ploxy{

               int *buf;

               int top;

 

               proxy(int _sz):top(_sz),buf(new int[_sz])

               {

                       cout << "ploxy()" << endl;

               }

               ~proxy()

               {

                       cout << "~ploxy()" << endl;

                       delete buf;

               }

        };

        int * buf;

        int top;

 

public:

 

        Stack(proxy a):buf(a.buf),top(a.top)

        {

               cout << "Stack()" << endl;

        }

};

 

void foo(Stack s)

{

        cout << "foo()" << endl;

}

 

void main()

{

        Stack s(10);

        foo(s);

        //foo(100); //error

}

 //////////////////////////////////////////////////////////////////////////
class
Stack

{

        int* buf;

        int top;

public:

        // 인자1개인생성자가암시적인변환의의미로사용되는것을막는다.

        // , 명시적변환은허용된다.

        explicit Stack( int sz = 10 ) {}

};

 

void foo( Stack s )

{

}

 

void main()

{

        Stack s;

        foo( s );

 

        foo( 100 );
         // 100 -> stack
이라면가능int->stack(변환생성자, 인자개인생성자!!

}

//////////////////////////////////////////////////////////////////////////
//
변환이야기.


void main()

{

        int n;

        cin >> n;      // 만약문자를입력하면실패한다.

 

        if( cin )
// cin.operaotr bool()
로변환되면가능하다. cin은객체이지만if문안에들어갈수이유는???

// 실제로는cin.operator void*()로되어있다.

        {

               cout << "성공" << endl;

        }

}
//////////////////////////////////////////////////////////////////////////

class Point

{

        int x;

        int y;

public:

        // 인자가1개인생성자=> 변환생성자라고불린다.

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

 

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

 

// 변환연산자: Point int로변하게된다. 리턴값을표기하지않는다. 함수이름에리턴값있다.!!

        operator int()

        {

               return x;

        }

};

 

void main()

{

        Point p( 1, 2 );

        int n = 10;

 

        p = n;                 // int -> Point로변환되게한다. 변환생성자

 

        double d = 3.2;

        int n = d;

 

        Point p1( 1, 2 );

 

        int n2 = p1;   // ?Point -> int로변환p1.operator int() 가있으면된다.

}

 

Tag |

7.26(목) C++ 기초문법 - ostream

from Study/C++ 2007/07/30 14:20 view 62662

#include <iostream>

using namespace std;

 

namespace AAA

{

        class Point

        {

               friend ostream& operator<<(ostream& os, const Point& aaa)

               {

                       return os;

               }

        };

 

}

 

void main()

{

        AAA::Point p;

 

//      AAA::operator<<(cout, p);
// error : cout.operator<<( AAA::Point),
처리하자!!

 

        cout << p;     // 인자기반탐색이가지는장점.!!

}

 

 

 

// cout, endl 의원리

#include <stdio.h>

 

class ostream

{

public:

        ostream& operator<<(char* s)

        {

               printf(s);

               return *this;

        }

        ostream& operator<<( ostream&(*f)(ostream&))

        {

               return f(*this);

        }

};

 

ostream cout;

///-----------------------------------------------------

ostream& endl(ostream& os)

{

        os << "\n";

        return os;

}

 

ostream& two_endl(ostream& os)        // ostream에확장가능하다!!!!

{

        os << "\n\n";

        return os;

}

 

void main()

{

        cout << "hello";       // cout.operator<<("hello")

        cout << two_endl;

        cout << endl;          // cout.operator<<(함수포인터)

        cout << "hello";       // cout.operator<<("hello")

 

        endl( cout );

}

 

Tag |

// 1. const_cast

int main()

{

        const int c = 10;

        int* p2 = const_cast<int*>(&c);
// error :
원본이 const이면 벗겨내지 못한다.

 

        int n = 10;

        const int* p = &n;  // ok

 

        int* p3 = const_cast<int*>(p);
//ok :
접근 하는 놈이 const이면 벗겨 낼 수 있다.     

}

// 2. 상수함수: 멤버의값을바꿀수없다.

// const 객체는const 함수만호출가능

// 반드시멤버의값을바꾸지않는다면const 함수로만들어라.

class Point

{

        int x;

        int y;

//      string cache;

//      bool   cache_valid;

 

        // 상수함수내에서도값을변경할수있다.

        mutable string cache;

        mutable bool   cache_valid;

 

public:

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

 

        string to_string() const

        {

               if( cache_valid == false )

               {

                       char buf[256];

                       sprintf( buf, "%d", "%d", x, y );

 

                       cache = buf;

                       cache_valid = true;

               }

               return cache;

        }

};

 

void main()

{

        const Point p(1, 2);

 

        cout << p.to_string() << endl;

}


 // 3. mutable을 사용하는 대신에 논리적 상수성을 사용한다.incrementation??
 // logical constness( 논리적 상수성. ) - lazy evaluation의 기법이기도 하다.

struct cache

{

        bool valid;

        string rep;

 

        cache(){ valid = false; }

};

 

class Point

{

        int x, y;

        cache* c;

 

public:

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

        {

               c = new cache();

        }

        ~Point()

        {

               if (c != NULL)

                       delete c;

        }

 

        string to_string() const

        {

               if ( c->valid == false )

               {

                       char buf[256];

                       sprintf( buf, "%d", "%d", x, y );

 

                       c->rep = buf;

                       c->valid = true;

               }

 

               return c->rep;

        }

 

};

 

void main()

{

        const Point p(1, 2);

 

        p.to_string();

}


Tag |

http://minjang.egloos.com/1458391 // 이문제에 대한 좋은 사례.

//
멤버함수 포인터의 크기, 가상함수 일때 크기, 상속이 있을때, 상속이 있을때 가상함수.

// 최대16byte 까지나온다. ??? boost??

 

// 다중상속과가상상속일때크기가달라집니다.

class  A

{

public:

        virtual void foo(int ) {}

};

class B : virtual public A

{

public:

        virtual void foo(int ){}

};

 

typedef void( B::*FUNC )();

 

void main()

{

        // 같은 표현
       
cout << sizeof( &B::foo ) << endl;

        cout << sizeof( FUNC ) << endl;
}

Tag |

// 일반 멤버 함수포인터를 만들 때에는 thiscall을 생각해서 'Point::'를 추가해주자!!
// void(Point::*f3)() = &Point::hoo;

class
Point

{

public:

        //this가인자로전달되지않는멤버함수.

        static void foo( int a )
        { cout << "foo()" << endl; }

        void hoo()

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

};

 

void goo( int a )

{

        cout << "goo()" << endl;
}

 

int main()

{

        void(*f1)(int) = &goo;

        void(*f2)(int) = &Point::foo;

 

        // 일반멤버함수의 주소

        void(Point::*f3)() = &Point::hoo;

 

        //f3(); // 될까? 안된다-> 객체가없다. this를전달해주지못한다.

 

        Point p;

        (p.*f3)();   // ().을 우선으로 연산하고 *를 하여서 함수포인터를 호출!

}

Tag |