2010-01-06 3 views
9

내가빈 클래스의 생성자를 호출하면 실제로 메모리가 사용됩니까?

class Empty{ 
    Empty(int a){ cout << a; } 
} 

같은 클래스가 그리고 나는 그것이

int main(){ 
    Empty(2); 
    return 0; 
} 

를 사용하여 호출 가정 윌 어떤 메모리는 "빈"객체의 생성에 대한 스택에 할당되는이 원인? 분명히 인수를 스택에 푸시해야하지만 추가 오버 헤드가 발생하지는 않습니다. 기본적으로 정적 멤버로 생성자를 사용하고 있습니다.

내가 이것을하고 싶은 이유는 템플릿 때문입니다. T의 유형을 지정하지 않아도 동안 나를, 그래서 하나 개의 템플릿 매개 변수를 전문으로 얻을

int main(){ 
    int a = 1; 
    FuncName<1>(a); 
} 

같은 것을 쓸 수있는

template <int which> 
class FuncName{ 
    template <class T> 
    FuncName(const T &value){ 
     if(which == 1){ 
      // specific behavior 
     }else if(which == 2){ 
      // other specific behavior 
     } 
    } 
}; 

처럼 실제 코드가 보인다. 또한, 나는 컴파일러가 생성자 안에서 다른 브랜치들을 최적화 할 수 있기를 바라고있다. 이것이 사실인지 또는 확인하는 방법을 아는 사람이라면 크게 환영 할 것입니다. 상황에 템플릿을 던지더라도 위에서 "빈 클래스"문제가 변경되지 않는다고 가정했습니다. 맞습니까?

+0

질문은 당신이 신경 쓰는 이유입니다.최상의 코드를 관리하고 생성하는 것은 컴파일러의 임무입니다. 가장 표현이 풍부한 코드를 작성하는 데 집중해야합니다. –

+0

추 신 : 인수가 스택에 푸시 될 필요는 없습니다. C++ ABI는 정의되지 않았기 때문에 컴파일러가 레지스터를 사용하여 매개 변수를 전달하는 작업을 수행하면 코드가 더 효과적입니다. –

+0

내가 얻을 수있는 최고의 성능을 원하기 때문에 신경 쓰지 않습니다. 나는 코드가 우아하고 이러한 것들에 대해 걱정하지 않아야한다는 태도를 정말로 싫어한다. 때로는 이러한 것들이 중요합니다 (고성능 컴퓨팅을 수행함). –

답변

16

인용 Stroustrup :

빈 클래스의 크기가 0이 아닌 이유는 무엇입니까? 두 개의 다른 오브젝트의 주소가 서로 다른지 확인하십시오. 같은 이유로 "new"는 항상 다른 객체에 대한 포인터를 반환합니다. 고려 :

class Empty { }; 

void f() 
{ 
    Empty a, b; 
    if (&a == &b) cout << "impossible: report error to compiler supplier"; 

    Empty* p1 = new Empty; 
    Empty* p2 = new Empty; 
    if (p1 == p2) cout << "impossible: report error to compiler supplier"; 
} 

빈 기본 클래스는 별도의 바이트로 표현 될 필요가 있다고 재미있는 규칙이있다 :

struct X : Empty { 
    int a; 
    // ... 
}; 

void f(X* p) 
{ 
    void* p1 = p; 
    void* p2 = &p->a; 
    if (p1 == p2) cout << "nice: good optimizer"; 
} 

이 최적화가 안전하고 가장 유용 할 수 있습니다. 프로그래머는 빈 클래스를 사용하여 오버 헤드없이 매우 간단한 개념을 표현할 수 있습니다. 현재 컴파일러 중 일부는이 "빈 기본 클래스 최적화"를 제공합니다.

+0

그러나 생성 된 객체가 전혀 참조되지 않으면 어떻게됩니까? 컴파일러는 스택 공간을 예약하지 않거나 범위를 벗어나지 않더라도 즉시 정리할 수 있습니까? –

+0

예, 컴파일러가 사용되지 않거나 참조되지 않은 경우 예약 된 메모리를 모두 제거한다고 확신합니다. 아주 간단한 최적화입니다. 컴파일러에 따라 다르다. –

+1

Behavior가 변경되지 않는 한 컴파일러는 객체의 전체 개념을 자유롭게 제거 할 수 있으며 모든 것이 레지스터에 저장된 코드와 모든 값에 인라 인될 수 있습니다. –

2

경우에 따라 다를 수 있습니다. 당신이 말하는 경우 :

Empty e; 
Empty * ep = & e; 

분명히 물건이 할당되어야합니다.

+0

컴파일러는 주소를 부여하기 위해 _allocate_ 코드를 반드시 방출해야합니까? & e가 힙이나 스택이 아닌 주소가 될 수없고 실제 개체가없는 주소가 될 수있는 이유가 있습니까? – James

+0

@Autopulated : 저는 그렇게 믿습니다. Richard Pennington의 의견을 참조하십시오. 더 흥미로운 질문은 당신이 그 주소를 결코 요구하지 않는다면이다; 그렇다면 여전히 하나가 있어야만 하는가? (매우 선하고 같은 질문) –

+1

당신이 e의 주소를 가지고 그 주소로 무언가를하면 (예제 코드에서는 그렇지 않습니다), e는 인스턴스화되어야합니다 - 즉 할당되어야합니다. –

2

시도해보십시오. 대부분의 컴파일러는 출력 최적화를 요청하면 이러한 임시 객체를 제거합니다. 다음 시도

void empty1 (int x) 
{ 
    using namespace std; 

    int a; 
    Empty e1 (x); 
    int b; 

    cout << endl; 
    cout << "empty1" << endl; 
    cout << hex << int (&x) << " " << dec << (&x - &a) << endl; 
    cout << hex << int (&a) << " " << dec << (&a - &b) << endl; 
} 

과 :

분해가 너무 복잡하다면, 다음과 같은 개체의 수가 다른 두 개의 함수를 작성하고 그들을 둘러싼 객체의 스택 위치에 어떤 차이가 있는지, 같은 것을 8 개의 Empties가 생성 된 empty8 기능과 비교할 때 실행됩니다. x86에서 g ++을 사용하면 빈 공간의 주소를 가져 가면 스택에서 x와 a 사이의 위치를 ​​얻을 수 있습니다. 따라서 출력에 x가 포함됩니다. 개체 저장소가 소스 코드에서 선언 된 것과 동일한 순서로 종료된다고 가정 할 수 없습니다.

+0

어떻게? 간단한 예제를 위해 g ++ 어셈블리 목록을보고 있는데 따라하기가 매우 어렵습니다. 'g ++ -c -g -O2 -Wa, -ahl = file.s file.cpp'을 사용하고 있습니다. –

+0

실행 파일 (디버그 정보 포함)을 더 잘 컴파일하고,'objdump -dS'를 사용하고, 관심있는 소스 라인을 검색하십시오. 최적화가 설정되었으므로 같은 소스 라인이 디스 어셈블리의 여러 위치에 나타나기 쉽습니다. –

관련 문제