[C++] 복사 생성자

Programming/C++ Language 2010. 5. 31. 11:34

복사 생성자는 지금까지의 평이한 내용에 비해 약간 난이도가 있는 내용이므로 정신을 집중해서 읽을 필요가 있다. 변수를 선언할 때 = 구분자 다음에 상수로 초기값을 지정할 수 있으며 이미 생성되어 있는 같은 타입의 다른 변수로도 초기화할 수 있다. 다음은 가장 간단한 타입인 정수형의 예이다.

int a=3;
int b=a; 

정수형 변수 a는 선언됨과 동시에 3으로 초기화되었다. 그리고 동일한 타입의 정수형 변수 b는 선언과 동시에 a로 초기화되었다. 결국 두 변수는 모두 3의 값을 가지게 될 것이다. 너무 너무 상식적인 코드이며 이런 초기화는 실수형이나 문자형, 구조체 등에 대해서도 똑같이 허용된다. 클래스가 int와 동일한 자격을 가지는 타입이 되기 위해서는 이미 생성되어 있는 같은 타입의 객체로부터 초기화될 수 있어야 한다. 객체에 대해서도 과연 이런 초기화가 성립할 수 있는지 Position 객체로 테스트해 보기 위해 Constructor 예제에 다음 코드를 작성해 보자. 

Position Here(30,10,'A');
Position There=Here;
There.OutPosition(); 

Here 객체가 먼저 (30,10) 위치의 문자 'A'를 가리키도록 초기화되었으며 이어서 There객체는 선언과 동시에 Here객체로 초기화되었다. 이때 멤버별 복사에 의해 There는 Here의 모든 멤버값을 그대로 복사받으며 두 객체는 완전히 동일한 값을 가지게 된다. Position 객체가 내부에 모든 정보를 포함하고 있기 때문에 이런 초기화는 전혀 문제가 없다. 그렇다면 모든 객체에 대해 이런 초기화가 가능한지 Person 객체로도 테스트해 보자. Person1 예제의 main 함수에 다음 테스트 코드를 작성한다. 

void main()
{
     Person Boy("강감찬",22);
     Person Young=Boy;
     Young.OutPerson();
} 

이 코드는 정상적으로 컴파일되며 실행도 되지만 종료할 때 파괴자에서 실행중 에러가 발생하는데 왜 그런지 보자. Young 객체가 Boy객체로 초기화될 때 멤버별 복사가 발생하며 Young의 Name멤버가 Boy의 Name과 동일한 번지를 가리키고 있다. 정수형인 Age끼리 값이 복사되는 것은 아무 문제가 없지만 포인터끼리의 복사는 문제가 된다. Young이 초기화된 직후의 메모리 상황을 그림으로 그려보면 다음과 같으며 두 객체가 힙에 동적 할당된 메모리를 공유하고 있는 모양이다.

이런 상태에서 Young.OutPerson이나 Boy.OutPerson 함수 호출은 아주 정상적으로 실행된다. 그러나 두 객체가 같은 메모리를 공유하고 있기 때문에 한쪽에서 Name을 변경하면 다른 쪽도 영향을 받게 되어 서로 독립적이지 못하다. 이 객체들이 파괴될 때 문제가 발생하는데 각 객체의 파괴자가 Name 번지를 따로 해제하기 때문이다. new는 Boy의 생성자에서 한 번만 했고 delete는 각 객체의 파괴자에서 두 번 실행하기 때문에 이미 해제된 메모리를 다시 해제하려고 시도하므로 실행중 에러가 된다. 정수형은 어떤지 보자.

int a=3;
int b=a;
b=5; 

b가 생성될 때 a의 값으로 초기화되어 a와 b는 같은 값을 가진다. 그러나 이는 어디까지나 초기화될 때 잠시만 같을 뿐이지 두 변수는 이후 완전히 독립적으로 동작한다. b에 5를 대입한다고 해서 a가 이 대입의 영향을 받지 않으며 a에 무슨 짓을 하더라도 b를 어찌할 수는 없다. 정수형의 복사 생성이 이처럼 독립적이므로 사용자 정의형도 이와 똑같이 복사 생성을 할 수 있어야 한다.

Person Young=Boy; 선언문에 의해 Young은 Boy의 멤버값을 복사받지만 이 때의 복사는 포인터를 그대로 복사하는 얕은 복사이다. 따라서 Young은 일시적으로 Boy와 같은 값을 가지지만 Boy의 Name을 빌려서 정보를 표현하는 불완전한 객체이며 독립적이지 못하다. 이 문제를 해결하려면 초기화할 때 얕은 복사를 해서는 안되며 깊은 복사를 해야 하는데 이때 복사 생성자가 필요하다. 얕은 복사가 문제의 원인이었으므로 깊은 복사를 하는 복사 생성자를 만들어 해결할 수 있다. 다음 예제는 Person1예제를 수정하여 Person 클래스에 복사 생성자를 추가한 것이다.  

: Person2

#include <Turboc.h> 

class Person
{
private:
     char *Name;
     int Age; 

public:
     Person(const char *aName, int aAge) {
         Name=new char[strlen(aName)+1];
         strcpy(Name,aName);
         Age=aAge;
     }

    Person(const Person &Other)   {
        Name=new char[strlen(Other.Name)+1];
        strcpy(Name,Other.Name);
        Age=Other.Age;
    }

     ~Person() {
          delete [] Name;
     }

     void OutPerson() {
          printf("이름 : %s 나이 : %d\n",Name,Age);
     }
};

 

void main()
{
     Person Boy("강감찬",22);
     Person Young=Boy;
     Young.OutPerson();
}

복사 생성자는 자신과 같은 타입의 다른 객체에 대한 레퍼런스를 전달받아 이 레퍼런스로부터 자신을 초기화한다. Person복사 생성자는 동일한 타입의 Other를 인수로 전달받아 자신의 Name에 Other.Name의 길이만큼 버퍼를 새로 할당하여 복사한다. 새로 메모리를 할당해서 내용을 복사했으므로 이 메모리는 완전한 자기 것이며 안전하게 따로 관리할 수 있다. Age는 물론 단순 변수이므로 값만 대입받으면 된다.

컴파일러는 Person Young=Boy; 구문을 Person Young=Person(Boy);로 해석하는데 이 원형에 맞는 생성자인 복사 생성자를 호출한다. 실인수 Boy가 Person 객체이므로 Person을 인수로 받아들이는 생성자 함수를 호출할 것이다. 복사 생성자에 의해 Young은 깊은 복사를 하며 메모리에 다음과 같이 완전한 사본을 작성한다.

이제 Young과 Boy는 타입만 같을 뿐 완전히 다른 객체이고 메모리도 따로 소유하므로 각자의 Name을 마음대로 바꿀 수 있고 파괴자에서 메모리를 해제해도 문제가 없다. 복사 생성자에 의해 두 객체가 완전한 독립성을 얻은 것이다.

복사 생성자의 임무는 새로 생성되는 객체가 원본과 똑같으면서 완전한 독립성을 가지도록 하는 것이다. 만약 객체가 데이터 베이스를 사용한다면 이 클래스의 복사 생성자는 새 객체를 위한 별도의 데이터 베이스 연결을 해야 하며 독점적인 자원을 필요로 한다면 마찬가지로 별도의 자원을 할당해야 한다. 그래야 Class A=B; 선언문에 의해 A가 B에 대해 독립적으로 초기화된다.

객체가 인수로 전달될 때

같은 종류의 다른 객체로 새 객체를 선언하는 경우는 그리 흔하지 않다. 그러나 다음과 같이 함수의 인수로 객체를 넘기는 경우는 아주 흔한데 이때도 복사 생성자가 호출된다. 

 void PrintAbout(Person AnyBody)
{
     AnyBody.OutPerson();
} 

void main()
{
     Person Boy("강감찬",22);
     PrintAbout(Boy);
}

 함수 호출 과정에서 형식 인수가 실인수로 전달되는 것은 일종의 복사생성이다. 함수 내부에서 새로 생성되는 형식인수 AnyBody가 실인수 Boy를 대입받으면서 초기화되는데 이때 복사 생성자가 없다면 AnyBody가 Boy를 얕은 복사하며 두 객체가 동적 버퍼를 공유하는 상황이 된다. AnyBody는 지역변수이므로 PrintAbout 함수가 리턴될 때 AnyBody의 파괴자가 호출되고 이때 동적 할당된 메모리가 해제된다. 이후 Boy가 메모리를 정리할 때는 이미 해제된 메모리를 참조하고 있으므로 에러가 발생할 것이다.

복사 생성자가 정의되어 있으면 AnyBody가 Boy를 깊은 복사하므로 아무런 문제가 없다. 객체가 인수로 전달될 때 뿐만 아니라 리턴값으로 돌려질 때도 복사 생성자가 호출된다. 위 테스트 코드를 Person2 예제에 작성해 놓고 실행하면 정상적으로 실행된다. 그러나 복사 생성자를 주석으로 묶어 버리면 다운된다. 함수의 인수로 사용되거나 리턴값으로 사용되는 객체는 반드시 복사 생성자를 제대로 정의해야 한다.

복사 생성자의 인수

복사 생성자의 인수는 반드시 객체의 레퍼런스여야 하며 객체를 인수로 취할 수는 없다. 만약 다음과 같이 Person형의 객체를 인수로 받아들인다고 해 보자.

 Person(const Person Other)
{
     Name=new char[strlen(Other.Name)+1];
     strcpy(Name,Other.Name);
     Age=Other.Age;
}

 복사 생성자 자신도 함수이므로 실인수를 전달할 때 값의 복사가 발생할 것이다. 객체 자체를 인수로 전달하면 복사 생성자로 인수를 넘기는 과정에서 다시 복사 생성자가 호출될 것이고 이 복사 생성자는 인수를 받기 위해 또 다시 복사 생성자를 호출한다. 결국 자기가 자신을 종료조건없이 호출해대는 무한 재귀 호출이 발생할 것이며 컴파일러는 이런 상황을 방관하지 않고 에러로 처리한다.

이런 이유로 복사 생성자의 인수로 객체를 전달할 수는 없다. 그렇다면 포인터의 경우는 어떨까? 포인터는 어디까지나 객체를 가리키는 번지값이므로 한 번만 복사되며 무한 호출되지 않는다. 또한 객체가 아무리 거대해도 단 4바이트만 전달되므로 속도도 빠르다. 복사 생성자가 객체의 포인터를 전달받도록 다음과 같이 수정해 보자.

 Person(const Person *Other) {
     Name=new char[strlen(Other->Name)+1];
     strcpy(Name,Other->Name);
     Age=Other->Age;
}

 Other의 타입이 Person *로 바뀌었고 본체에서 Other의 멤버를 참조할 때 . 연산자 대신 -> 연산자를 사용하면 된다. 그러나 이렇게 하면 Person Young=Boy; 선언문이 암시적으로 호출하는 생성자인 Person(Boy)와 원형이 맞지 않다. 사실 포인터를 취하는 생성자는 복사 생성자로 인정되지도 않는다. 꼭 포인터로 객체를 복사하려면 main의 객체 선언문이 Person Young=&Boy;가 되어야 하는데 그래야 Person 복사 생성자로 Boy의 번지가 전달된다. main 함수까지 같이 수정하면 정상적으로 잘 동작한다.

그러나 이는 일반적인 변수 선언문과 형식이 일치하지 않는다. 기본 타입의 복사 생성문을 보면 int i=j; 라고 하지 int i=&j;라고 선언하지는 않는다. 즉 포인터를 통한 객체 복사 구문은 C 프로그래머가 알고 있는 상식적인 변수 선언문과는 틀리다. 클래스가 기본형과 완전히 같은 자격의 타입이 되려면 int i=j; 식으로 선언할 수 있어야 한다.

그래서 객체 이름에 대해 자동으로 &를 붙이고 함수 내부에서는 전달받은 포인터에 암시적으로 *연산자를 적용하는 레퍼런스라는 것이 필요해졌다. 복사 생성자가 객체의 레퍼런스를 받으면 Young=Boy라고 써도 실제로는 포인터인 &Boy가 전달되어 속도 저하나 무한 호출없이 기본 타입과 똑같은 형식의 선언이 가능하다. 이후 공부하게 될 연산자 오버로딩에도 똑같은 이유로 레퍼런스가 활용된다. C에서는 꼭 필요치 않았던 레퍼런스라는 개념이 C++에서는 필요해진 이유가 객체의 선언문, 연산문을 기본 타입과 완전히 일치시키기 위해서이다.

복사 생성자로 전달되는 인수는 상수일 수도 있고 아닐 수도 있는데 내부에서 읽기만 하므로 개념적으로 상수 속성을 주는 것이 옳다. int i=j; 연산 후 j의 값이 그대로 유지되어야 한다. 결론만 요약하자면 Class 클래스의 복사 생성자 원형은 Class(const Class &)여야 한다.

디폴트 복사 생성자

클래스가 복사 생성자를 정의하지 않으면 컴파일러가 디폴트 복사 생성자를 만든다. 컴파일러가 만드는 디폴트 복사 생성자는 멤버끼리 1:1로 복사함으로써 원본과 완전히 같은 사본을 만들기만 할 뿐 깊은 복사를 하지는 않는다. 만약 디폴트 복사 생성자만으로 충분하다면(Position 클래스의 경우) 굳이 복사 생성자를 따로 정의할 필요는 없다. 이때 만들어지는 디폴트 복사 생성자는 다음과 같을 것이다.

 Position(const Position &Other) {
     x=Other.x;
     y=Other.y;
     ch=Other.ch;
} 

대응되는 멤버끼리 그대로 대입하는데 전부 단순 타입이라 대입만 하면 잘 복사된다. 이런 디폴트 복사 생성자가 있기 때문에 별도의 조치가 없어도 Position There=Here가 잘 동작하는 것이다.

또한 Class A=B; 식의 선언을 하지 않거나 객체를 함수의 인수로 사용할 일이 전혀 없다는 것이 확실하다면 이때도 복사 생성자가 필요없다. 그러나 이런 가정은 무척 위험할 수 있다. 왜냐하면 클래스의 사용자는 클래스가 일반 타입과 동등하므로 int, double에서 가능한 일들은 클래스에 대해서도 모두 가능하다고 기대하며 실제로 그런 코드를 작성하기 때문이다. 이 기대에 부응하기 위해 클래스는 모든 면에서 기본 타입과 완전히 같아야 한다.

Person2 예제에서 복사 생성자를 정의함으로써 Person 클래스는 이미 생성된 객체로부터 새로운 객체를 선언할 수 있게 되었다. Person 클래스가 점점 기본 타입과 같아지고 있지만 이 클래스는 아직까지도 불완전하다. Person 클래스가 완전한 타입이 되려면 대입 연산자를 재정의해야 하는데 이 실습은 다음에 다시 해 보도록 하자.

출처 : www.winapi.co.kr

설정

트랙백

댓글

new int(3) 과 new int[3]

Programming/C Language 2010. 5. 27. 19:41
계속 C 만 쓰다가 C++ 을 만질 때가 와서 코드를 보다가 순간 동적 할당 문법이 맞나 하는 노파심에 네이버 지식인에 검색을 했는데 아래와 같이 잼있는 질문이 있어서 올린다.

질문

new int(3) 이거하고
new int[3] 이거하고
구체적인 차이가 뭔가요...
좀 갈켜주세요 좀 자세히..


답변
new int(3) 메모리를 int형으로 할당하고 3으로 초기화
new int[3] 메모리를 int형으로 3개 할당. 배열이군요.  


뭐.. 다들 보면 딱 알겠지만 너무 오랜만에 봐서 그런가 어라.. 저게 맞나? 하는 생각도 들었었다 ㅋㅋ 역시 사람의 머리란.. ㅎ C++ 처음부터 공부한다는 생각으로 다시 기본부터 열심히 봐야겠다. ㅎㅎ

'Programming > C Language' 카테고리의 다른 글

#if  (0) 2010.05.27
구조체 정렬  (0) 2009.09.27
#include 와 #define 의 순서  (0) 2009.08.18
매크로 함수  (0) 2009.08.18
코딩 스타일  (0) 2009.08.15

설정

트랙백

댓글

[C++] Construct method

Programming/C++ Language 2010. 5. 27. 19:38
Resource leak 을 방지하기 위해, 생성자에서 할당(Allocation) 로직을 빼고, 이를 Construct 함수에 넣자. 즉, 생성자에서는 변수들을 초기화를 하고, Construct 함수를 만들어서 Construct 함수에서 할당 로직을 작성하도록 하자는 것이다. 생성자에 할당(Allocation) 로직을 넣었을 경우, 만에 하나 생성자가 실행 중일 때, 프로그램이 죽을 경우 소멸자가 호출되지 않음으로써 Resource leak 이 발생 할 수 있다.

TestClass::TestClass()
{
__abc = 0;
__pStr = "Test";
}

TestClass::Construct()
{
__ptr = new char( 10 );
}

int main()
{
TestClass Test = new TestClass();
Test.Construct();
return 0;
}


 

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

[C++] Errors : cannot allocate an object of abstract type '???'  (0) 2010.06.14
[C++] 복사 생성자  (0) 2010.05.31
[C++] static_cast  (0) 2010.03.22
[C++] const  (0) 2010.03.19
[C++] 다양한 생성자 초기화 방법  (0) 2010.03.19

설정

트랙백

댓글

#if

Programming/C Language 2010. 5. 27. 17:29

#ifdef, #ifndef는 매크로의 존재 여부만으로 컴파일 조건을 판단하며 매크로가 어떤 값으로 정의되어 있는지는 평가하지 않는다. 이에 비해 #if는 매크로의 값을 평가하거나 여러 가지 조건을 결합하여 컴파일 여부를 결정하는 좀 더 복잡한 전처리문이다. #ifdef보다는 사용법이 조금 까다롭지만 C 언어의 조건문과 유사하므로 쉽게 익힐 수 있다. 기본 형식은 다음과 같다. 

#if 조건1
코드
1           // 조건1을 만족하면 코드1을 컴파일
#elif 조건2
코드
2           // 조건 2가 만족되면 코드2를 컴파일
#else
코드
3           // 둘 다 맞지 않으면 코드 3을 컴파일
#endif

1 ) 매크로값을 비교할 때는 상등, 비교 연산자를 사용한다. 같다, 다르다는 ==, != 연산자를 사용하며 대소를 비교할 때는 >, <, >=, <= 비교 연산자가 사용된다.

#if (LEVEL == 3)
#if (VER >= 7)

조건문은 꼭 괄호로 싸지 않아도 상관없지만 C의 조건문에 익숙한 개발자들은 #if에도 가급적 괄호를 붙여 주는 편이며 괄호가 있는 편이 보기에도 안정감이 느껴져 좋다. #if는 조건문이 참일 때 1로, 거짓일 때 0으로 평가하는데 결과가 0이 아니면 이어지는 코드 블록을 컴파일한다. 이 점도 C와 동일하다.

2 ) 비교 대상은 정수 상수여야 하며 실수나 문자열은 매크로와 비교할 수 없다. 컴파일러에 따라 실수 비교를 허용하는 것들도 있는데 조건부 컴파일을 통제하는 매크로는 대소가 있는 값이라기 보다는 주로 표식이기 때문에 실수는 별로 실용성이 없다고 할 수 있다. 정수값을 가지는 다른 매크로와 값을 비교하는 것은 가능하다.

#if (VER == 3.14)             // 에러
#if (NAME == "Kim")          // 에러
#if (LEVEL == BASIC)       // 가능 

버전 번호 같은 경우에 1.0, 1.5같이 실수로 표기하지만 매크로 상수로 버전을 표시할 때는 100, 150 등과 같이 정수화해서 사용하는 것이 일반적이다.

3 ) 수식 내에서 간단한 사칙 연산을 할 수 있다. 전처리기가 연산문을 평가한 후 그 결과를 비교하므로 다소 복잡한 식은 굳이 결과를 계산해 넣을 필요없이 수식을 바로 써도 상관없다. 

#if (LEVEL*2 == 6)
#if (TIME == 365*24) 

나머지 연산, 비트 연산 등도 가능하다. 그러나 ++, --, 포인터 연산, sizeof, 캐스트 연산 등은 사용할 수 없다. 이런 연산들은 전처리문에서 불가능하거나 의미가 없기 때문이다. 매크로는 상수이므로 좌변값이 아니며 sizeof 연산자는 컴파일시에 평가된다. 전처리는 컴파일 이전의 단계임을 명심하도록 하자.

4 ) 논리 연산자로 두 개 이상의 조건을 동시에 평가할 수 있다. C언어의 논리 연산자와 같은 &&, ||, !를 그대로 사용하면 된다. 

#if (LEVEL == 8 && VER != 3) 

세 개 이상의 조건도 물론 평가할 수 있다. 이때 필요하다면 조건 평가의 우선 순위 지정을 위해 괄호를 사용한다.

5 ) defined 연산자로 매크로의 존재 여부를 평가할 수 있다. #if defined(MACRO) 전처리문은 #ifdef MACRO와 완전히 동일한 문장이다. 그러나 다른 조건과 함께 매크로의 존재 여부를 평가할 때는 #ifdef를 쓸 수 없으므로 defined 연산자가 따로 제공된다. 

#if (LEVEL == 8 || defined(PROFESSIONAL) )

defined 연산자는 전처리문내에서만 사용되므로 일반 C코드에서는 사용할 수 없다.

6 )  #if 다음의 조건부 컴파일 블록에는 어떤 문장이든지 올 수 있다. a=b+c; 연산문이나 함수 호출문, int i; 같은 선언문은 물론이고 struct tag_A { ~ 같은 정의문도 올 수 있다. 심지어 #include, #define같은 다른 전처리문도 조건부 컴파일(정확하게 표현한다면 조건부 전처리) 대상이 될 수 있다. 그렇다면 #if안에 또 다른 #if문이 올 수 있다는 얘기가 되며 즉 #if는 중첩가능한 전처리문이다.

#if (LEVEL == 8)
LEVEL이 8일 때의 코드
#if (VER > 5)
버전이 5보다 클 때의 코드
#endif
LEVEL이 8일 때의 코드
#endif 

#if안에 #ifdef가 올 수도 있고 반대도 가능하며 중첩 깊이에 제한도 없다. 조건속에 또 다른 조건이 있는 것은 자연스러운 것이므로 전처리기는 당연히 조건부 컴파일문의 중첩을 허용한다. 단, 전처리문이 중복될 경우 짝이 되는 #endif가 반드시 존재해야 한다는 것만 주의하면 된다. #endif는 조건부 컴파일 대상의 끝을 명시하는 중요한 역할을 한다. C 코드는 블록이 중첩될 때 적당히 들여쓰기를 하지만 조건부 컴파일 지시자가 중첩될 경우 들여쓰기는 하지 않는 것이 보통이다.

다음은 #if의 활용예를 보자. 어떤 문제를 해결하는데 세 가지(또는 그 이상) 방법이 있고 각 방법을 적용했을 때의 성능을 테스트해 보려고 한다. 이때 각 방법의 코드를 지웠다 넣었다 할 필요없이 다음과 같이 조건부 컴파일문으로 작성해 놓으면 METHOD 매크로만 변경하여 적용할 방법을 쉽게 선택할 수 있다. 이 코드가 다른 프로그램의 부품으로 사용되는 라이브러리이고 고객마다 선호하는 방법이 다르다면 모든 코드를 소스에 둔 채 고객의 주문대로 조건부 컴파일하기만 하면 된다. 

#define METHOD 1
#if (METHOD == 1)
방법1
#elif (METHOD == 2)
방법2
#else
방법3
#endif 

#if 0도 주석 대신 흔히 사용되는 구문이다. 아주 긴 소스를 잠시 주석 처리해 놓고 싶을 때는 이 부분을 #if 0 .... #endif로 감싸 버리면 항상 거짓이므로 전처리기에 의해 이 코드는 없는 것으로 취급된다. /* */ 주석은 중첩될 수 없어 긴 소스를 주석 처리할 때 불편한 반면 #if 0는 중첩 가능하기 때문에 이런 문제가 없다.

출처 : www.winapi.co.kr

'Programming > C Language' 카테고리의 다른 글

new int(3) 과 new int[3]  (0) 2010.05.27
구조체 정렬  (0) 2009.09.27
#include 와 #define 의 순서  (0) 2009.08.18
매크로 함수  (0) 2009.08.18
코딩 스타일  (0) 2009.08.15

설정

트랙백

댓글

트랜잭션 [ transaction ] 이란?

Programming/Network 2010. 5. 27. 15:09

①상점에서의 고객의 주문이나 판매, 은행에서의 예금주의 입금이나 출금과 같은 하나의 외부 거래를 기록하기 위해 컴퓨터 시스템 내부에서 완료되어야 하는 일련의 처리 동작. 트랜잭션에는 파일 내용의 갱신, 수신 응답의 통보 등이 포함된다. 트랜잭션 데이터단말기를 통해 입력되는 경우, 하나의 트랜잭션은 단말기와 트랜잭션 응용 프로그램을 작동시키는 컴퓨터 시스템 간의 몇 번의 메시지 교환으로 이루어지기도 한다.
②외부 거래를 기록하기 위해 단말기 등에서 생성하여 컴퓨터 시스템으로 전송되는 데이터. 트랜잭션 데이터와 같은 의미로 사용된다.
데이터베이스에 대한 조회나 갱신 조작의 열로 구성되는 처리의 기본 단위. 갱신에 의해 일시적으로 부정합되는 데이터베이스 내의 데이터가 이용자에게 사용되지 않도록 하기 위해 적절한 구분 기호로 일련의 조작을 한데 묶어서 처리한다. 트랜잭션은 원자성, 정합성, 고립성, 내구성 등의 특성에 의해 실행의 정당성이 보증된다.


'Programming > Network' 카테고리의 다른 글

HTTP and WWW  (0) 2010.08.21
프록시 서버( proxy server )  (0) 2010.08.21
HTTP Method  (0) 2010.06.06
Post/Redirect/Get  (1) 2010.05.31
세션 [ session ] 이란?  (0) 2010.05.27

설정

트랙백

댓글

세션 [ session ] 이란?

Programming/Network 2010. 5. 27. 14:39

①망 환경에서 사용자 간 또는 컴퓨터 간의 대화를 위한 논리적 연결.
②프로세스들 사이에서 통신을 하기 위해 메시지 교환을 통해 서로를 인식한 이후부터 통신을 마칠 때까지의 기간.

'Programming > Network' 카테고리의 다른 글

HTTP and WWW  (0) 2010.08.21
프록시 서버( proxy server )  (0) 2010.08.21
HTTP Method  (0) 2010.06.06
Post/Redirect/Get  (1) 2010.05.31
트랜잭션 [ transaction ] 이란?  (0) 2010.05.27

설정

트랙백

댓글

[excel] 다양한 엑셀 데이터 다루기

Tools/Excel 2010. 4. 5. 10:29
Ctrl + ; ( 세미콜론 )
: 현재 날짜를 입력하고자 할 경우

Ctrl + Shift + ; ( 세미콜론 )
: 현재 시간을 입력하고자 할 경우

사용자 지정 목록( 사용자가 원하는 채우기 핸들 목록 작성 )
: MS Excel Key -> Excel 옵션 -> 사용자 지정목록 편집 -> 새목록을 클릭하고, 목록항목에 원하는 항목을 연속으로 적고, 추가를 누르고 확인.

숫자 + 문자 : 채우기 핸들시
: 숫자만 자동으로 증가

'Tools > Excel' 카테고리의 다른 글

[EXCEL] OFFSET 함수  (0) 2010.10.17
[EXCEL] MATCH 함수  (0) 2010.10.17
[Excel] 이름 정의  (0) 2010.10.12

설정

트랙백

댓글

가죽 손질법

Life 2010. 3. 28. 22:51

가죽손질법
집에서 누구나 손쉽게 할수있는 가죽손질법 하나로 반영구적으로 입을수 있는 가죽옷!

 

먼지, 오물 제거법
먼지나 오물로 더러워진 가죽옷은 면이나 스펀지에 콜드크림을 묻혀 닦아주면 때도 말끔히 닦일뿐아니라 가죽원단이 촉촉해지고 윤택이 난다.

 

가죽 주름 제거법
가죽에 주름이 잡혔을때는 광목(면)을 깔고 다림질 한다. 온도가 높아지면 가죽이 눌러붙을 우려가 있으므로 다리미 온도는 중간으로 맞춰준다.

 

물묻은 가죽 손질법
가죽옷이 비나 눈에 맞아 물이 묻었을때 마른수건으로 두들기듯 닦아준다. 물이 마르면 가죽이 딱딱해질수 있는데 이럴때는 양손으로 비벼주면 부드러워진다. 단, 물이 묻었을때 문질러 닦으면 가죽이 벗겨질수 있으므로 두드려 닦아주는것이 좋다.

 

가죽 낙서 제거법
낙서등으로 부분적인 얼룩이 생겼을때 쉽게 구할수 있는 지우개로 때를 지워준다. 굳이 세탁소를 찾지않아도 말끔하게 얼룩을 지워진다.

 

가죽옷 리폼 - 부분수선
낡고 유행지난 가죽옷을 리폼한다! 부분적으로 찢어졌거나 낡은 가죽옷은 디자인을 변경해 수선할수있다. 지퍼장식이나 단추장식, 비슷한 천이나 가죽을 덧대어 사용하는법 등 취향에 따라 골라 리폼할수있다.

 

가죽옷 리폼 - 디자인변경
유행지난 가죽옷 리폼하기! 크기를 줄이거나 디자인을 변경해 다양하게 입을수있다. 최신유행 칼라로 바꾸고싶다면 원하는 디자인을 종이모형으로 제작해 비슷한 가죽원단을 잘라 칼라를 만들고 박음질로 처리해 수선한다.

 

가죽 리폼비용
가죽쟈켓 리폼비용은 2~4만원 사이! 저렴한 가격으로 올가을 가죽멋쟁이가 되보자~


설정

트랙백

댓글

undefined reference

Programming 2010. 3. 26. 16:36
undefined reference 라고 뜨는 것은 컴파일 에러가 아니라 링크 에러 이다. -_-;

그러니, 소스 만지고 있지 말고, 프로젝트에 가서 해당 에러부분과 관련된 라이브러리 파일을 연결 시켜주도록 하자.

이거 때문에 몇 시간 동안, 열 내면서 혼자 벅벅 거렸네 ;; 에휴... 수명이 몇 년은 줄은거 같다..

죽을때 까지 안까먹겠지..

'Programming' 카테고리의 다른 글

세마포어( Semaphore )  (1) 2010.05.31
Event-driven programming  (0) 2010.05.31
XML 이란?  (0) 2010.03.26
serialize ( 직렬화 )  (0) 2010.03.22
시리얼 통신  (0) 2009.10.19

설정

트랙백

댓글

XML 이란?

Programming 2010. 3. 26. 13:07
XML( Extensible Markup Language ) 은 전자적으로 인코딩한 문서를 위해 만들어놓은 규칙의 일련이다. XML은 목표는 인터넷을 통한 간결함, 일반성, 사용성을 강조한다. 이는 전세계의 언어를 위해 유니코드를 통한 강력한 지원을 하는 문자 데이터 포맷이다. 비록 문서에 XML이 문서에 집중한 디자인일 지라도, 이는 웹사이트 처럼, 임의의 자료구조의 표현을 위해 널리 사용되고 있다.
S/W 개발자들이 XML 데이터를 접근하기위해 사용하는 다양한 programming interface 들과 다양한 XML기반 언어의 정의를 지원하기위해 디자인된 schema system 들이 있다.
2009년 부터, 수백개의 XML기반 언어들이 개발되었다......

위의 내용은 wiki 의 내용을 대략 번역한 내용이다. 원문은 아래의 링크를 따라 가보도록 하자.

http://en.wikipedia.org/wiki/Xml

'Programming' 카테고리의 다른 글

Event-driven programming  (0) 2010.05.31
undefined reference  (0) 2010.03.26
serialize ( 직렬화 )  (0) 2010.03.22
시리얼 통신  (0) 2009.10.19
뉴욕의 프로그래머  (0) 2009.09.04

설정

트랙백

댓글