2012-10-05 6 views
6

서브 루틴의 범위 밖에서 정의되어야한다고해도 서브 루틴의 끝에서 클래스에 대해 호출되는 소멸자에 문제가 있습니다.C++ : 소멸자가 범위를 벗어나기 전에 호출되고 있습니까?

#include <iostream> 
using namespace std; 

class Foo { 
private: 

    double *array; 

public: 

Foo(int N) { 
    array = new double[N]; 
    for (int i=0; i<N; i++) { 
     array[i]=0; 
    } 
} 

~Foo() { 
    delete[] array; 
} 
}; 

void subroutine(Foo x) { 
    cout << "Hello!" << endl; 
} 

int main() { 
    Foo bar(10); 
    subroutine(bar); 
    subroutine(bar); 
} 

지금 여기에 첫 번째 서브 루틴 후 호출되는 객체 막대의 소멸자가이 범위는 전체해야 비록 완료 : 여기

내 문제를 표시 내가 가진 코드의 작은 조각이다 주요 기능? 즉, 두 번째 서브 루틴을 호출하면 소멸자가 다시 호출되고 메모리 누수가 발생합니다.

서브 루틴에서 참조로 호출하여이 문제를 해결할 수 있지만 처음에는 작동하지 않는 이유를 이해할 수 없기 때문에이 픽스에 만족하지 않습니다. 누군가 나를 위해이 일을 밝힐 수 있습니까?

감사합니다.

+2

소멸자가 주어지면'Foo'의 복사 생성자와 복사 할당 연산자를 정의하거나 삭제해야합니다. "rule of three"로 검색하십시오. –

+5

"클래스에 대해 소멸자가 호출되었습니다"- ** 클래스 **와 ** 객체 **를 일관되게 구별하면 시간이 지남에 따라 훨씬 더 명확 해집니다. 소멸자는 클래스가 아닌 ** 객체 **에서 호출됩니다. –

답변

21

subroutine 함수에 값으로 Foo을 전달합니다. 이것은 자신의 복사본을 가지고 있다는 것을 의미합니다.이 복사본은 범위를 벗어나면 파괴됩니다. 여기

void subroutine(Foo x) { 
    // x is a new Foo here. It will get destroyed on exiting scope, 
    // resulting in a destructor call 
} 

귀하의 주요 문제는 복사 생성자를 구현하지 않은, 그래서 동적으로 할당 된 배열 (그것이 가리키는 포인터 만)를 복사되지 않는 것입니다. 따라서 Foo 개체를 복사하면 각 복사본이 동일한 배열을 참조하게됩니다. 그리고 각 사본은 그것을 파괴하려고합니다.

rule of three을 따르고 각 배열 Foo 개체가 자체 배열을 소유하도록 배열의 "전체 복사본"을 만드는 할당 연산자와 복사 생성자를 구현해야합니다.

+0

아 답장을 보내 주셔서 감사합니다. 예, 참고로 전화를 걸었지만 그 이유를 모르겠다는 것을 알았습니다. 설명해 주셔서 감사합니다! – Plog

+1

@ user1722882 : 실제로'std :: vector'를 사용하는 것이 더 좋을 것이고 소멸자를 완전히 제거하는 것이 좋습니다. 표준 라이브러리 컨테이너를 다시 구현하면 운동에 도움이 될 수 있지만 운동/직업의 주된 목적이 아닌 경우 생산성이 저하됩니다. –

1

당신이 겪고있는 문제는 당신이 값으로 개체를 전달하는 것입니다 :

void subroutine(Foo x) { 

이 임시 객체를 생성하고 객체의 복사 생성자/소멸자 당신이 그것을 호출 할 때마다 호출된다.

3

void subroutine(Foo x) {을 호출하면 bar 개체가 복사됩니다 (따라서 소멸자는 함수 완료 후 호출됩니다).

사용 시도 : void subroutine(Foo &x) {, 잘 작동합니다.

6

값을 기준으로 서브 루틴에 전달하므로 복사본이 생성됩니다. 만드는 피하기 위해 사본을 참조로 전달할 :

void subroutine(Foo& x) 
{ 
    cout << "Hello!" << endl; 
} 

당신은 복사 생성자를 선언하여 클래스의 실수로 사본을 방지하고이 같은 할당 연산자의 개인 복사 할 수 있습니다 :

class Foo { 
private: 

    double *array; 

    Foo(const Foo&); 
    Foo& operator=(const foo&); 

public: 
    ... 
}; 

는 그런 다음 편집을 얻기를 대신 오류. 실제로 클래스의 복사본을 만들 수 있어야한다면 실제로 "딥 복사본"을 수행하기 위해 이러한 함수를 구현해야합니다 (또는 std::vector<float>을 사용하고 안전한 복사를 포함하여 메모리를 관리하도록하는 것이 더 좋습니다).

+0

with C++ 11 대신 '삭제됨'으로 선언하는 것이 좋습니다. –

관련 문제