Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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 31
Tags more
Archives
Today
Total
관리 메뉴

Pure Software Engineer :)

[항목5] C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자 본문

Software Engineering/Programming

[항목5] C++가 은근슬쩍 만들어 호출해 버리는 함수들에 촉각을 세우자

HelloJaewon 2014. 1. 7. 17:56

C++은 개발자가 클래스에 직접 넣지 않더라도 자동으로 생성하는 함수들이 있다. 그것들은 바로

1. 복사 생성자(copy constructor)

2. 복사 대입 연산자(copy assignment operator)

3. 소멸자(destructor)

 

위의 3가지에 더하여, 어떠한 생성자도 선언되지 있지 않으면 다음도 생성한다.

4. 기본 생성자

 

위 1~4가지의 공통점은 모두 public 멤버라는 것과 inline 함수라는 것이다.

 

즉, 다음 두 코드 블럭은 동일하다.

 

 

 
1
class Empty {};

 

 

 
1
2
3
4
5
6
7
8
9
class Empty {
public:
    Empty () { ... }
    Empty (const Empty & rhs) { ... }
    ~Empty () { ... }
 
    Empty & operator= (const Empty & rhs) { ... }
};
 

 

C++ 컴파일러는 컴파일시 코드를 분석해서, 필요한 경우 코드들을 생성해내는 것이다.

 

기본 생성자의 경우, 어떠한 생성자라도 선언되어 있지 않다면 생성되기때문에, 다음과 같은 코드는 컴파일에러는 발생하게 된다.

Empty 클래스 안에는 생성자가 선언되어 있으므로, 컴파일러는 기본 생성자를 만들어내지 않는다.

 

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <cstdio>
 
class Empty {
public:
    Empty (int x);
 
private:
    int m_x;
};
 
int main () {
    Empty e;
 
    return 0;
}
 
그렇다면 컴파일러가 생성해내는 코드가 하는 일은 무엇일까?
 
1. 복사 생성자

각 멤버 변수에 대해 복사생성자 호출(클래스인 경우) 또는 각 비트를 그대로 복사(기본제공 타입인 경우)를 수행한다.

 

2. 복사 대입 연산자

근본적으로는 복사 생성자와 동작원리가 같다.

하지만, 다음과 같은 특별한 경우를 고려해 보아야 한다.

 

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
 
class NamedObject {
public:
    NamedObject (std::string & name, const int & value);
 
private:
    std::string & nameValue;
    const int     objectValue;
};
 
int main () {
    std::string newDog("alice");
    std::string oldDog("bob");
 
    NamedObject p(newDog, 2);
    NamedObject s(oldDog, 30);
 
    p = s;
}

 

위의 코드를 컴파일하면 19번째줄에서 다음과 같은 컴파일에러가 발생한다

error C2582: 'operator =' function is unavailable in 'NamedObject'

 

그 이유는 NamedObject 클래스의 멤버인 nameValue와 objectValue가 각각 참조자 및 상수이기 때문이다.

참조자와 상수는 한번 값이 정해지면 변경할 수 없기 때문이다.

따라서 컴파일러는 에초에 이러한 상황을 컴파일 타임에 알아채서 에러는 발생시켜주는 것이다.

즉, 참조자를 데이터 멤버로 갖고 있는 클래스에 대입 연산을 지원하려면 직접 복사 대입 연산자를 정의해 주어야 한다.

'Software Engineering > Programming' 카테고리의 다른 글

[Refactoring] What is refactoring?  (0) 2014.05.17
[C] namespace  (0) 2014.01.29
[C, C++] Compile time assertion  (0) 2013.12.12
[항목49] new 처리자의 동작 원리를 제대로 이해하자  (0) 2013.07.20
Effective C++  (0) 2013.07.20