문제

C++ 프로그램에서 메모리 누수를 방지하기 위한 일반적인 팁은 무엇입니까?동적으로 할당된 메모리를 누가 해제해야 하는지 어떻게 알 수 있나요?

도움이 되었습니까?

해결책

메모리를 수동으로 관리하는 대신 해당되는 경우 스마트 포인터를 사용해 보십시오.
다음을 살펴보세요. 부스트 라이브러리, TR1, 그리고 스마트 포인터.
또한 스마트 포인터는 이제 C++ 표준의 일부입니다. C++11.

다른 팁

나는 RAII 및 스마트 포인터에 대한 모든 조언을 전적으로 지지하지만 약간 더 높은 수준의 팁도 추가하고 싶습니다.관리하기 가장 쉬운 메모리는 할당한 적이 없는 메모리입니다.거의 모든 것이 참조인 C# 및 Java와 같은 언어와 달리 C++에서는 가능할 때마다 개체를 스택에 배치해야 합니다.Stroustrup 박사를 포함하여 여러 사람들이 지적한 것처럼 C++에서 가비지 수집이 결코 인기가 없었던 주된 이유는 잘 작성된 C++가 애초에 많은 가비지를 생성하지 않는다는 것입니다.

쓰지 마세요

Object* x = new Object;

또는

shared_ptr<Object> x(new Object);

그냥 쓸 수 있을 때

Object x;

사용 라이

  • 가비지 컬렉션은 잊어버리세요 (대신 RAII를 사용하세요).Garbage Collector도 누출될 수 있으며(Java/C#에서 일부 참조를 "null"하는 것을 잊어버린 경우) 가비지 수집기는 리소스를 처리하는 데 도움이 되지 않습니다(객체에 대한 핸들을 획득한 경우). 파일의 경우 Java에서 수동으로 수행하지 않거나 C#에서 "dispose" 패턴을 사용하지 않으면 개체가 범위를 벗어날 때 파일이 자동으로 해제되지 않습니다.
  • "함수당 하나의 반환" 규칙을 잊어버리세요.이는 누출을 방지하기 위한 좋은 C 조언이지만 예외 사용으로 인해 C++에서는 오래되었습니다(대신 RAII 사용).
  • 그리고 동안 "샌드위치 패턴" 좋은 C 조언입니다. C++에서는 오래되었습니다 예외를 사용하기 때문입니다(대신 RAII를 사용하십시오).

이번 포스팅은 반복되는 것 같지만, C++에서 알아야 할 가장 기본적인 패턴은 라이.

Boost, TR1 또는 심지어 낮은 수준의(하지만 종종 충분히 효율적인) auto_ptr에서 스마트 포인터를 사용하는 방법을 배우십시오(하지만 한계를 알아야 합니다).

RAII는 C++의 예외 안전성과 리소스 처리의 기초이며 다른 패턴(샌드위치 등)은 두 가지를 모두 제공하지 않습니다. 대부분의 경우 아무 것도 제공하지 않습니다.

RAII 코드와 비 RAII 코드의 비교는 아래를 참조하세요.

void doSandwich()
{
   T * p = new T() ;
   // do something with p
   delete p ; // leak if the p processing throws or return
}

void doRAIIDynamic()
{
   std::auto_ptr<T> p(new T()) ; // you can use other smart pointers, too
   // do something with p
   // WON'T EVER LEAK, even in case of exceptions, returns, breaks, etc.
}

void doRAIIStatic()
{
   T p ;
   // do something with p
   // WON'T EVER LEAK, even in case of exceptions, returns, breaks, etc.
}

에 대한 라이

요약하자면 (의 의견 이후 오우거 시편 33편), RAII는 세 가지 개념을 사용합니다.

  • 객체가 생성되면 작동합니다! 생성자에서 리소스를 획득하세요.
  • 객체 파괴만으로 충분합니다! 소멸자에서 무료 리소스를 사용하세요.
  • 범위에 관한 모든 것입니다! 범위가 지정된 개체(위의 doRAIIStatic 예제 참조)는 선언 시 생성되며 종료(반환, 중단, 예외 등) 방법에 관계없이 실행이 범위를 종료하는 순간 삭제됩니다.

이는 올바른 C++ 코드에서는 대부분의 개체가 다음을 사용하여 생성되지 않음을 의미합니다. new, 대신 스택에 선언됩니다.그리고 다음을 사용하여 구성된 사람들의 경우 new, 모든 것이 어떻게든 될 것입니다 범위가 지정된 (예:스마트 포인터에 부착).

개발자로서 이는 수동 리소스 처리(C에서 수행된 것처럼 또는 집중적으로 사용하는 Java의 일부 객체에 대해 신경 쓸 필요가 없기 때문에 실제로 매우 강력합니다. try/finally 그런 경우에는)...

편집 (2012-02-12)

"범위가 지정된 개체 ...파괴될 것이다...출구에 상관없이" 그것은 전적으로 사실이 아닙니다.RAII를 속이는 방법이 있습니다.Terminate()의 모든 종류는 정리를 우회합니다.이탈(EXIT_SUCCESS)은 이와 관련하여 모순적입니다.

빌헬름텔

빌헬름텔 그것에 대해서는 아주 옳습니다.있다 특별한 RAII를 속이는 방법으로 인해 프로세스가 갑자기 중단됩니다.

사람들은 특별한 C++ 코드는 종료, 종료 등으로 가득 차 있지 않거나 예외가 있는 경우에는 처리되지 않은 예외 프로세스를 충돌시키고 메모리 이미지를 있는 그대로 코어 덤프합니다. 청소 후에는 그렇지 않습니다.

그러나 그런 경우는 거의 발생하지 않지만 여전히 발생할 수 있기 때문에 우리는 이러한 경우에 대해 알아야 합니다.

(누가 전화해? terminate 또는 exit 캐주얼 C++ 코드에서?...나는 놀 때 그 문제를 다루어야 했던 것을 기억한다. 과다:이 라이브러리는 매우 C 지향적이므로 C++ 개발자가 신경 쓰지 않는 등의 일을 어렵게 만들기 위해 적극적으로 설계합니다. 스택 할당 데이터, 또는 "흥미로운" 결정을 내리거나 메인 루프에서 돌아오지 않음...이에 대해서는 언급하지 않겠습니다).

다음과 같은 스마트 포인터를 살펴보는 것이 좋습니다. 부스트의 스마트 포인터.

대신에

int main()
{ 
    Object* obj = new Object();
    //...
    delete obj;
}

Boost::shared_ptr은 참조 카운트가 0이 되면 자동으로 삭제됩니다.

int main()
{
    boost::shared_ptr<Object> obj(new Object());
    //...
    // destructor destroys when reference count is zero
}

제가 마지막으로 언급한 바에 따르면, "참조 횟수가 0일 때 이것이 가장 멋진 부분입니다.따라서 개체의 사용자가 여러 명인 경우 개체가 아직 사용 중인지 추적할 필요가 없습니다.아무도 공유 포인터를 참조하지 않으면 공유 포인터가 삭제됩니다.

그러나 이것이 만병통치약은 아니다.기본 포인터에 액세스할 수 있더라도 그것이 수행하는 작업에 대해 확신이 없다면 이를 타사 API에 전달하고 싶지 않을 것입니다.많은 경우, 생성 범위가 완료된 후 작업을 수행하기 위해 다른 스레드에 항목을 "게시"합니다.이는 Win32의 PostThreadMessage에서 일반적입니다.

void foo()
{
   boost::shared_ptr<Object> obj(new Object()); 

   // Simplified here
   PostThreadMessage(...., (LPARAM)ob.get());
   // Destructor destroys! pointer sent to PostThreadMessage is invalid! Zohnoes!
}

언제나 그렇듯, 어떤 도구를 사용하든 사고력을 활용하세요...

계속 읽어보세요 라이 그리고 당신이 그것을 이해했는지 확인하십시오.

대부분의 메모리 누수는 객체 소유권과 수명이 명확하지 않기 때문에 발생합니다.

가장 먼저 해야 할 일은 가능할 때마다 스택에 할당하는 것입니다.이는 특정 목적을 위해 단일 객체를 할당해야 하는 대부분의 경우를 다룹니다.

객체를 '새'로 만들어야 하는 경우 대부분의 경우 남은 수명 동안 확실한 단일 소유자를 갖게 됩니다.이 상황에서 나는 포인터로 저장된 객체를 '소유'하도록 설계된 여러 컬렉션 템플릿을 사용하는 경향이 있습니다.이는 STL 벡터 및 맵 컨테이너로 구현되지만 몇 가지 차이점이 있습니다.

  • 이러한 컬렉션은 복사하거나 할당할 수 없습니다.(객체가 포함된 경우)
  • 객체에 대한 포인터가 삽입됩니다.
  • 컬렉션이 삭제되면 먼저 컬렉션의 모든 개체에 대해 소멸자가 호출됩니다.(파괴되고 비어 있지 않은지 확인하는 다른 버전이 있습니다.)
  • 포인터를 저장하므로 상속된 개체를 이러한 컨테이너에 저장할 수도 있습니다.

STL의 장점은 대부분의 응용 프로그램에서 개체가 해당 컨테이너에서 사용하는 데 필요한 의미 있는 복사 의미 체계가 없는 고유 엔터티인 반면 값 개체에 너무 집중한다는 것입니다.

으, 어린 아이들과 신예 쓰레기 수집가들...

"소유권"에 대한 매우 강력한 규칙 - 어떤 개체 또는 소프트웨어의 일부가 개체를 삭제할 권한을 가지고 있는지를 나타냅니다.포인터가 "소유"하는지 또는 "그냥 보기만 하고 만지지 마세요"인지 명확하게 하기 위해 주석과 현명한 변수 이름을 지우십시오.누가 무엇을 소유하는지 결정하는 데 도움이 되도록 모든 서브루틴이나 메서드 내에서 가능한 한 "샌드위치" 패턴을 따르십시오.

create a thing
use that thing
destroy that thing

때로는 매우 다양한 장소에서 생성하고 파괴해야 하는 경우도 있습니다.나는 그것을 피하기가 어렵다고 생각합니다.

복잡한 데이터 구조가 필요한 모든 프로그램에서는 "소유자" 포인터를 사용하여 다른 객체를 포함하는 엄격하고 명확한 객체 트리를 만듭니다.이 트리는 응용 프로그램 도메인 개념의 기본 계층 구조를 모델링합니다.예를 들어 3D 장면은 개체, 조명, 텍스처를 소유합니다.프로그램이 종료될 때 렌더링이 끝나면 모든 것을 파괴할 수 있는 명확한 방법이 있습니다.

배열 등을 스캔하기 위해 한 엔터티가 다른 엔터티에 액세스해야 할 때마다 필요에 따라 많은 다른 포인터가 정의됩니다.이것은 "그냥 보는 것"입니다.3D 장면 예의 경우 개체는 텍스처를 사용하지만 소유하지는 않습니다.다른 객체도 동일한 텍스처를 사용할 수 있습니다.객체의 파괴는 ~ 아니다 모든 텍스처의 파괴를 호출합니다.

예, 시간이 많이 걸리지만 그게 제가 하는 일입니다.메모리 누수나 기타 문제가 거의 발생하지 않습니다.하지만 저는 고성능 과학, 데이터 수집 및 그래픽 소프트웨어라는 제한된 분야에서 일하고 있습니다.저는 은행이나 전자 상거래, 이벤트 중심 GUI 또는 높은 네트워크 비동기 혼돈과 같은 거래를 자주 처리하지 않습니다.어쩌면 새로운 방식이 거기에 이점을 줄 수도 있습니다!

좋은 질문입니다!

C++를 사용하고 게임과 같은 실시간 CPU 및 메모리 보드 애플리케이션을 개발하는 경우 자체 메모리 관리자를 작성해야 합니다.

다양한 작가의 흥미로운 작품을 병합하는 것이 더 나은 방법이라고 생각합니다. 몇 가지 힌트를 드릴 수 있습니다.

  • 고정 크기 할당자는 인터넷 어디에서나 많이 논의됩니다.

  • Small Object Allocation은 2001년 Alexandrescu의 완벽한 저서 "Modern C++ design"에서 소개되었습니다.

  • 훌륭한 발전(소스 코드 배포 포함)은 Dimitar Lazarov가 작성한 "고성능 힙 할당자"라는 Game 프로그래밍 Gem 7(2008)의 놀라운 기사에서 찾을 수 있습니다.

  • 훌륭한 리소스 목록은 다음에서 찾을 수 있습니다. 이것 기사

쓸모없는 멍청한 할당자를 직접 작성하지 마세요...먼저 자신을 문서화하십시오.

C++의 메모리 관리에 널리 사용되는 기술 중 하나는 다음과 같습니다. 라이.기본적으로 생성자/소멸자를 사용하여 리소스 할당을 처리합니다.물론 C++에는 예외 안전성으로 인해 몇 가지 불쾌한 세부 사항이 있지만 기본 아이디어는 매우 간단합니다.

문제는 일반적으로 소유권 문제로 귀결됩니다.나는 Scott Meyers의 Effective C++ 시리즈와 Andrei Alexandrescu의 Modern C++ Design을 읽어볼 것을 적극 권장합니다.

누출을 방지하는 방법에 대해서는 이미 많은 내용이 있지만 누출을 추적하는 데 도움이 되는 도구가 필요한 경우 다음을 살펴보세요.

어디에서나 사용자 스마트 포인터를 사용할 수 있습니다!모든 종류의 메모리 누수가 사라집니다.

프로젝트 전체에서 메모리 소유권 규칙을 공유하고 알아보세요.COM 규칙을 사용하면 최상의 일관성이 보장됩니다([in] 매개 변수는 호출자가 소유하며 호출 수신자는 복사해야 합니다.[out] 매개변수는 호출자가 소유하며, 참조를 유지하는 경우 호출자는 복사본을 만들어야 합니다.등.)

발그린드 런타임 시 프로그램 메모리 누수를 확인하는 데도 좋은 도구입니다.

대부분의 Linux(Android 포함)와 Darwin에서 사용할 수 있습니다.

프로그램에 대한 단위 테스트를 작성하는 경우, 테스트에서 valgrind를 체계적으로 실행하는 습관을 들여야 합니다.잠재적으로 초기 단계에서 많은 메모리 누수를 방지할 수 있습니다.또한 일반적으로 전체 소프트웨어에서 수행하는 간단한 테스트에서 이를 정확히 찾아내는 것이 더 쉽습니다.

물론 이 조언은 다른 메모리 검사 도구에도 유효합니다.

또한 표준 라이브러리 클래스가 있는 경우 수동으로 할당된 메모리를 사용하지 마세요(예:벡터).가상 소멸자가 있다는 규칙을 위반했는지 확인하십시오.

무언가에 대해 스마트 포인터를 사용할 수 없거나 사용할 수 없는 경우(비록 큰 위험 신호임에도 불구하고) 다음과 같이 코드를 입력하십시오.

allocate
if allocation succeeded:
{ //scope)
     deallocate()
}

당연한 말이지만 꼭 입력하세요 ~ 전에 범위에 코드를 입력하면

이러한 버그의 빈번한 원인은 개체에 대한 참조 또는 포인터를 허용하지만 소유권이 불분명한 상태로 유지되는 메서드가 있는 경우입니다.스타일과 주석 처리 규칙을 사용하면 이런 일이 발생할 가능성이 줄어듭니다.

함수가 객체의 소유권을 갖는 경우를 특별한 경우로 두십시오.이런 일이 발생하는 모든 상황에서는 이를 나타내는 헤더 파일의 함수 옆에 주석을 작성해야 합니다.대부분의 경우 객체를 할당하는 모듈이나 클래스가 객체 할당 해제도 담당하는지 확인하도록 노력해야 합니다.

const를 사용하면 어떤 경우에는 많은 도움이 될 수 있습니다.함수가 객체를 수정하지 않고 객체가 반환된 후에도 지속되는 참조를 저장하지 않는 경우 const 참조를 허용합니다.호출자의 코드를 읽으면 함수가 개체의 소유권을 수락하지 않았음을 알 수 있습니다.동일한 함수가 const가 아닌 포인터를 허용하도록 할 수 있었고 호출자는 피호출자가 소유권을 수락했다고 가정할 수도 있고 가정하지 않을 수도 있지만 const 참조를 사용하면 의문의 여지가 없습니다.

인수 목록에 const가 아닌 참조를 사용하지 마십시오.호출자 코드를 읽을 때 호출 수신자가 매개변수에 대한 참조를 유지했을 수 있다는 것은 매우 불분명합니다.

참조 계산 포인터를 권장하는 의견에 동의하지 않습니다.이는 일반적으로 잘 작동하지만 버그가 있고 작동하지 않는 경우, 특히 소멸자가 다중 스레드 프로그램과 같이 사소하지 않은 작업을 수행하는 경우에는 더욱 그렇습니다.너무 어렵지 않다면 참조 계산이 필요하지 않도록 디자인을 조정하십시오.

중요한 순서대로 팁:

-Tip#1 소멸자를 "가상"으로 선언하는 것을 항상 기억하세요.

-팁#2 RAII를 사용하세요

-팁#3 부스트의 스마트포인터를 사용하세요

-Tip#4 버그가 있는 스마트 포인터를 직접 작성하지 말고 부스트를 사용하세요(지금 진행 중인 프로젝트에서는 부스트를 사용할 수 없으며 스마트 포인터를 디버깅해야 하는 어려움을 겪었기 때문에 절대 사용하지 않을 것입니다) 같은 경로를 다시 사용하지만 지금 당장은 종속성을 강화할 수 없습니다.)

-팁#5 캐주얼하거나 성능이 중요하지 않은 경우(수천 개의 객체가 있는 게임 등) 작업이 Thorsten Ottosen의 부스트 포인터 컨테이너를 살펴보세요.

-Tip#6 시각적 누출 감지의 "vld" 헤더와 같이 선택한 플랫폼에 대한 누출 감지 헤더를 찾으세요.

가능하다면 Boost shared_ptr 및 표준 C++ auto_ptr을 사용하십시오.이는 소유권 의미를 전달합니다.

auto_ptr을 반환하면 호출자에게 메모리 소유권을 부여한다고 알리는 것입니다.

shared_ptr을 반환하면 호출자에게 이에 대한 참조가 있고 소유권의 일부를 가지지만 이는 전적으로 호출자의 책임이 아니라는 것을 알리는 것입니다.

이러한 의미는 매개변수에도 적용됩니다.호출자가 auto_ptr을 전달하면 소유권을 부여하는 것입니다.

다른 사람들은 처음에 메모리 누수를 방지하는 방법(예: 스마트 포인터)을 언급했습니다.그러나 프로파일링 및 메모리 분석 도구는 메모리 문제가 발생했을 때 추적할 수 있는 유일한 방법인 경우가 많습니다.

Valgrind memcheck 훌륭한 무료 제품입니다.

MSVC의 경우에만 각 .cpp 파일의 맨 위에 다음을 추가합니다.

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

그런 다음 VS2003 이상으로 디버깅할 때 프로그램이 종료될 때 누수에 대한 메시지가 표시됩니다(새 항목/삭제 추적).기본적이지만 과거에는 도움이 되었습니다.

valgrind(*nix 플랫폼에서만 사용 가능)는 매우 훌륭한 메모리 검사기입니다.

메모리를 수동으로 관리하려는 경우에는 두 가지 경우가 있습니다.

  1. 나는 객체를 생성하고(아마도 새 객체를 할당하는 함수를 호출하여 간접적으로) 그것을 사용하고(또는 내가 호출한 함수가 그것을 사용함) 그것을 해제합니다.
  2. 누군가 나에게 참조를 주었으므로 이를 해제해서는 안 됩니다.

이러한 규칙을 위반해야 하는 경우 이를 문서화하세요.

포인터 소유권에 관한 것입니다.

  • 개체를 동적으로 할당하지 않도록 하세요.클래스에 적절한 생성자와 소멸자가 있는 한 클래스 유형에 대한 포인터가 아닌 클래스 유형의 변수를 사용하고 컴파일러가 자동으로 수행하므로 동적 할당 및 할당 해제를 피할 수 있습니다.
    실제로 이는 "스마트 포인터"에서 사용되는 메커니즘이기도 하며 일부 다른 작성자에서는 RAII라고 합니다 ;-).
  • 객체를 다른 함수에 전달할 때 포인터보다 참조 매개변수를 선호하세요.이렇게 하면 발생할 수 있는 몇 가지 오류를 피할 수 있습니다.
  • 가능하다면 매개변수 const를 선언하세요. 특히 객체에 대한 포인터를 선언하세요.그렇게 하면 객체가 "우연히" 해제될 수 없습니다(const를 캐스트하는 경우는 제외 ;-))).
  • 프로그램에서 메모리 할당 및 할당 해제를 수행하는 위치 수를 최소화하십시오.이자형.g.동일한 유형을 여러 번 할당하거나 해제하는 경우 해당 유형에 대한 함수(또는 팩토리 메소드 ;-))를 작성하십시오.
    이렇게 하면 필요한 경우 쉽게 디버그 출력(주소 할당 및 할당 취소 등)을 생성할 수 있습니다.
  • 팩토리 함수를 사용하여 단일 함수에서 여러 관련 클래스의 개체를 할당합니다.
  • 클래스에 가상 소멸자가 있는 공통 기본 클래스가 있는 경우 동일한 함수(또는 정적 메서드)를 사용하여 모든 클래스를 해제할 수 있습니다.
  • purify(불행히도 많은 $/€/...)와 같은 도구를 사용하여 프로그램을 확인하십시오.

메모리 할당 기능을 가로채서 프로그램 종료 시 해제되지 않은 일부 메모리 영역이 있는지 확인할 수 있습니다. 모두 응용 프로그램).

또한 new 연산자와 delete 연산자, 기타 메모리 할당 함수를 대체하여 컴파일 타임에 수행할 수도 있습니다.

예를 들어 이것을 확인하십시오 대지 C ++의 메모리 할당 디버깅] 참고 :삭제 연산자에 대한 트릭도 다음과 같습니다.

#define DEBUG_DELETE PrepareDelete(__LINE__,__FILE__); delete
#define delete DEBUG_DELETE

일부 변수에 파일 이름을 저장할 수 있으며 오버로드된 삭제 연산자가 해당 파일이 호출된 위치를 알게 됩니다.이 방법으로 프로그램의 모든 삭제 및 malloc을 추적할 수 있습니다.메모리 검사 시퀀스가 ​​끝나면 할당된 메모리 블록이 '삭제'되지 않았음을 보고할 수 있어야 하며 이를 파일 이름과 줄 번호로 식별해야 합니다. 이것이 바로 귀하가 원하는 것입니다.

다음과 같은 것을 시도해 볼 수도 있습니다. 경계 검사기 꽤 흥미롭고 사용하기 쉬운 Visual Studio에서.

우리는 앞에 간단한 문자열을 추가하고 끝에 센티넬 플래그를 추가하는 레이어로 모든 할당 기능을 래핑합니다.예를 들어 "myalloc( pszSomeString, iSize, iAlignment );또는 new( "설명", iSize ) MyObject();내부적으로 지정된 크기와 헤더 및 센티널을 위한 충분한 공간을 할당합니다.물론, 디버그 빌드가 아닌 경우에는 이를 주석 처리하는 것을 잊지 마세요!이를 수행하려면 메모리가 조금 더 필요하지만 비용보다 이점이 훨씬 큽니다.

여기에는 세 가지 이점이 있습니다. 첫째, 특정 '영역'에 할당된 코드를 빠르게 검색하지만 해당 영역이 해제되어야 할 때 정리되지 않음으로써 어떤 코드가 유출되고 있는지 쉽고 빠르게 추적할 수 있습니다.모든 센티널이 손상되지 않았는지 확인하여 경계가 덮어쓰기된 시기를 감지하는 것도 유용할 수 있습니다.이는 잘 숨겨진 충돌이나 배열 실수를 찾으려고 할 때 많은 시간을 절약해 주었습니다.세 번째 이점은 누가 큰 플레이어인지 확인하기 위해 메모리 사용을 추적하는 것입니다. 예를 들어 '사운드'가 예상보다 훨씬 더 많은 공간을 차지하는 경우 MemDump의 특정 설명 조합을 통해 알려줍니다.

C++는 RAII를 염두에 두고 설계되었습니다.제 생각에는 C++에서 메모리를 관리하는 데 이보다 더 좋은 방법은 없습니다.그러나 로컬 범위에 매우 큰 청크(예: 버퍼 개체)를 할당하지 않도록 주의하세요.스택 오버플로가 발생할 수 있으며, 해당 청크를 사용하는 동안 경계 검사에 결함이 있는 경우 다른 변수나 반환 주소를 덮어쓸 수 있어 모든 종류의 보안 허점이 발생할 수 있습니다.

다른 위치에 할당하고 삭제하는 방법에 대한 유일한 예 중 하나는 스레드 생성(전달하는 매개변수)입니다.하지만 이 경우에도 쉽습니다.스레드를 생성하는 함수/메서드는 다음과 같습니다.

struct myparams {
int x;
std::vector<double> z;
}

std::auto_ptr<myparams> param(new myparams(x, ...));
// Release the ownership in case thread creation is successfull
if (0 == pthread_create(&th, NULL, th_func, param.get()) param.release();
...

대신 스레드 함수

extern "C" void* th_func(void* p) {
   try {
       std::auto_ptr<myparams> param((myparams*)p);
       ...
   } catch(...) {
   }
   return 0;
}

꽤 쉽지 않나요?스레드 생성이 실패하는 경우 리소스는 auto_ptr에 의해 해제(삭제)됩니다. 그렇지 않으면 소유권이 스레드에 전달됩니다.스레드가 너무 빨라서 생성 후 리소스를 해제하기 전에 리소스를 해제하면 어떻게 될까요?

param.release();

메인 함수/메서드에서 호출되나요?아무것도 아님!왜냐하면 우리는 auto_ptr에게 할당 해제를 무시하라고 '지시'할 것이기 때문입니다.C++ 메모리 관리는 쉽죠?건배,

에마!

다른 리소스(핸들, 파일, DB 연결, 소켓...)를 관리하는 것과 동일한 방식으로 메모리를 관리합니다.GC도 도움이 되지 않습니다.

모든 함수에서 정확히 하나의 반환이 발생합니다.그렇게 하면 거기에서 할당 해제를 수행하고 절대 놓치지 않을 수 있습니다.

그렇지 않으면 실수하기가 너무 쉽습니다.

new a()
if (Bad()) {delete a; return;}
new b()
if (Bad()) {delete a; delete b; return;}
... // etc.
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top