2014-10-14 2 views
-1

저는 C++을 배우기 시작할 것입니다. 그리고 이것은 메모리 누출이나 일종의 부두 마술이라는 것을 이해하지 못합니까?!삭제 된 객체에 정적 함수를 호출하십시오.

나는 (단지 데모) 일부 "싱글"클래스가 있습니다

Create S 
S::S 
S::a 
S::~S 
S::a 

그래서 내 질문은

: 왜 소멸자 호출 후에 나는 여전히 작동 한

이들의
#include <iostream> 
using namespace std; 

class S { 
    private: S() { 
     cout << "S::S" << endl; 
    } 

    public: static S* instance() { 
     static S* i; 
     if(i == NULL) { 
      cout << "Create S" << endl; 
      i = new S; 
     } 
     return i; 
    } 

    public: virtual ~S() { 
     cout << "S::~S" << endl; 
    } 

    public: void a() { 
     cout << "S::a" << endl; 
    } 
}; 

int main() { 
    // call some method 
    S::instance()->a(); 
    // delete pointer to instance (no reason, because I'm curious) 
    delete S::instance(); 
    // call method again 
    S::instance()->a(); 

    return 0; 
} 

출력이를 정적 변수에서 클래스 S의 복사본?

업데이트 : 답변 해 주셔서 감사합니다. 나는 내 실수를 깨닫는다. 제발 저를 용서해주십시오.

+3

당신은 작업 복사본이없는, 당신은 BTW (.. A * 매달려 * 포인터가 정말 정의되지 않은 동작을 유발하는 메소드 * this is java .. – Nim

+1

(btw - 다운 유권자에게 - 초급자에게 투표하기가 다소 힘든 이유 - 특별히 이유가 없다!) – Nim

+1

'메모리 누출인지 또는 어떤 종류인지 이해하지 못합니다. of voodoo magic'결론은 C + +에서 대부분의 다른 언어와 달리 "나쁜 일"을한다고해서 코드가 충돌하고, 스택 추적을 얻으며, "당신이 나쁜 짓을 한 것"이라는 메시지 상자가 나타납니다. 등등. 그래서 당신이 얻고있는 해답은 귀하의 질문에 적용 할 수 있지만 오류없이 컴파일 할 수있는 "열매가 많은"C++ 코드가 있지만 괜찮습니다. – PaulMcKenzie

답변

2

인스턴스에 대한 두 번째 호출은 지금 위험하다 :

S::instance()->a(); 

그것은 호출합니다 :

public: static S* instance() { 
    static S* i; 
    if(i == NULL) { 
      cout << "Create S" << endl; 
     i = new S; 
    } 
    return i; 
} 

하지만 난이 NULL이 아닌 (삭제 개체 수 있지만, 포인터가 유효하지 않습니다) 그래서 한 번 포인터가 S 인 일부 메모리에 대한 포인터를 반환합니다. 그리고 나서 의 정의되지 않은 동작이있을 수 있습니다. 예전의 객체가있을 수도 있고 그렇지 않을 수도 있습니다.

결론이 기능을 사용하려면 개체를 삭제할 때 항상 포인터를 NULL로 설정해야합니다. 예를 들어,이 대답을 확인하십시오. How to delete Singleton pointer?

+0

나는 당신의 대답을 더 좋아합니다. . 당신은 내가 놓친 것에 끌 렸고 아마도 OP가 실제로 알고 싶어하는 것일 것입니다 : 왜 인스턴스()가 재구성을 일으키지 않았는가? –

+0

확인. 나는 그것을 얻는다 (나는 실생활에서 그러한 코드를 결코 사용하지 않을 것이다). 하지만 프로그램 끝에서 소멸자를 호출하지 않는 이유는 무엇입니까? – lxmarduk

+0

'S :: a'다음에요? 포인터이기 때문에 직접 지워야합니다. 귀하의 OS 또는 IDE는 프로그램에서 사용하는 메모리를 해제하기 때문에 소멸자를 호출 할 필요가 없습니다. – RvdK

0

"작동중인 인스턴스"가 없습니다. 정의되지 않은 동작 (파괴 된 개체에 액세스하는 중입니다)이 있습니다. a()이 어떤 식 으로든 개체의 데이터 멤버에 액세스하지 않기 때문에 정상적으로 작동하는 것처럼 보입니다. 그러나 기술적으로는 매달려있는 포인터를 역 참조하고 있고, segfault를 포함하여 어떤 일이 일어날 수 있습니다.

사례가 약간 씩 다르지만 (스택에 매달려있는 포인터가 아니라 액세스 후 삭제가 있음) 부실 포인터에 대해 excellent answer을 읽는 것이 좋습니다.


서식 관련 참고 사항 : 코드 레이아웃이 확실히 합법적이지만 C++ 개발자에게는 매우 외국어로 읽습니다. 다음은 더 자연스러운 형식입니다.

class S { 
    S() { 
     cout << "S::S" << endl; 
    } 

public: 
    static S* instance() { 
     static S* i; 
     if(i == NULL) { 
      cout << "Create S" << endl; 
      i = new S; 
     } 
     return i; 
    } 

    virtual ~S() { 
     cout << "S::~S" << endl; 
    } 

    void a() { 
     cout << "S::a" << endl; 
    } 
}; 
0

파괴 된 개체를 사용하면 정의되지 않은 동작이 발생하므로 사용하지 마십시오. 그것이 결정할 때까지 ... 일하는 것을 포함하여 어떤 일이 일어날 수 있습니다.

그 언어의 정답입니다. 일반적으로 이런 종류의 정의되지 않은 동작이 발생하는 이유는 멤버 함수가 일단 기계 코드로 변환 된 일반 함수이기 때문입니다. 실제적으로 클래스 멤버를 사용하지 않는다면 폭발하지 않을 것입니다.

하지만 다시 동작이입니다. 작동하지 않을 것으로 기대하지 마십시오.

0

다른 대답과 마찬가지로 코드에서 정의되지 않은 동작이 있습니다. 간단한 코드로 코드가 실제로 제대로 작동하는지 확인할 수 있습니다.

배쉬 : 라인 7 :

하지만 여전히이 발생할 수 있습니다 ./a.out 7324 분할 오류 (덤프 코어) 대부분의 코드베이스에서 코드는 훨씬 더 복잡하고, 같은 버그 결과입니다 코드의 다른 부분에서는 버그가있는 곳과 관련이 없으며 즉시 그렇지 않습니다.

나는 그런 출력을 허용하기 위해 약간 코드를 수정했습니다. 보시다시피,이 코드에서 더 많은 할당이 있고 이것은 아마도 segfault를 일으키는 것입니다. 즉, 벡터가 아마도 S :: ss의 일부를 재사용하고 있다는 의미입니다. 메모리가 해제되어 S에서 사용 된 덤프가 충돌하게됩니다. 에이. `* 각하기 전에 : 공용`필요가 없습니다 -

http://coliru.stacked-crooked.com/a/c1be7a83275ae847

#include <iostream> 
#include <vector> 
#include <string> 
using namespace std; 

class S { 
    std::string ss; 
    private: S() { 
     ss = "ub ub ub ub ub ub ub ub "; 
     cout << "S::S" << endl; 
    } 

    public: static S* instance() { 
     static S* i; 
     if(i == NULL) { 
      cout << "Create S" << endl; 
      i = new S; 
     } 
     return i; 
    } 

    public: virtual ~S() { 
     cout << "S::~S" << endl; 
    } 

    public: void a() { 
     cout << "S::a" << ss << endl; 
    } 
}; 

int main() { 
     S::instance()->a(); 
     // delete pointer to instance (no reason, because I'm curious) 
     delete S::instance();  
    for (int n = 0; n < 100; ++n){ 
     std::vector<char> avec(n); 
     // call some method 
     S::instance()->a(); 
    } 

    return 0; 
} 
관련 문제