2008-08-26 13 views
8

저는 대학에서 사용하지 않은 객체는 항상 비워야하지만 실제 사용 방법은 배제해야한다는 것을 알았습니다. 예를 들어 코드를 올바르게 구조화하는 등의 작업을 수행 할 수 있습니다. C++에서 포인터를 처리하는 방법에 대한 일반적인 규칙이 있습니까?C++ 메모리 관리

나는 현재 부스트를 사용할 수 없습니다. 나는 순수한 C++을 고수해야한다. 왜냐하면 내가 사용하고있는 프레임 워크가 제네릭을 사용하는 것을 금지하기 때문이다.

+0

너무 오래 됐습니다. 왜 제네릭을 사용할 수 없는지에 대한 설명을 듣고 싶습니다. – jmucchiello

+0

프레임 워크의 설명서에서 : 템플릿을 사용하지 마십시오. 다른 운영 체제, 특히 컴파일러 및 링크 편집기에서 지원하는 방식으로 이식 할 수 없습니다. 그것은 현재 내가 말할 수있는 전부다. –

+0

템플릿은 2009 년에 다른 운영 체제에서 잘 지원되었는데, OS가 거의 유능한 컴파일러를 사용할 수있는 한. 프레임 워크를 작성하는 사람은 자신의 주장에 대한 실제 증거를 제시 할 수 있어야합니다. –

답변

14

필자는 개발자 계약을 기반으로 우수한 시스템을 갖춘 임베디드 심비안 OS를 사용 해왔다.

  1. 하나의 개체 만 포인터를 소유합니다. 기본적으로 이것은 작성자입니다.
  2. 소유권을 이전 할 수 있습니다. 소유권이 넘어 갔음을 나타 내기 위해 객체는 메소드 서명 (예 : void Foo (Bar * zonk);)의 포인터로 전달됩니다.
  3. 소유자가 개체 삭제시기를 결정합니다.
  4. 개체를 사용하기 위해 메서드에 전달하려면 개체가 메서드 서명 (예 : void Foo (Bat & zonk);)의 참조로 전달됩니다.
  5. 비 소유자 클래스는 소유자가 사용 중에이를 파기하지 않는다고 확신 할 수있을 때만 주어지는 객체에 대한 참조 (포인터가 아님)를 저장할 수 있습니다.

기본적으로 클래스는 단순히 무언가를 사용하는 경우 참조를 사용합니다. 클래스가 무언가를 소유하고 있다면 포인터를 사용합니다.

이것은 아름답게 작동했으며 사용하기가 즐거웠습니다. 메모리 문제는 매우 드뭅니다.

+0

나는 소유자 배가 (RAW 포인터가 아니라) 전송 중임을 보여주기 위해 std :: auto_ptr <>을 사용했다. 아마도 단독 소유권이 기대된다면 이미 스마트 포인터에 저장하고있을 것입니다. std :: auto_ptr <>은 완벽합니다. –

+0

OP는 제네릭을 사용할 수 없다고 말했고 아마도 스마트 포인터 유형을 배제 할 것입니다. –

+0

실수로 참조가 가리키는 객체를 삭제하면 응용 프로그램 코어 덤프가 발생하지 않습니까? 만약 그것이 포인터라면 null을 검사 할 수 있습니다 (deleter가 null로 설정했다면). – balki

5

규칙 :

  1. 가능한 경우는 smart pointer를 사용합니다. 부스트 일부는 good ones입니다.
  2. 스마트 포인터를 사용할 수없는 경우 null out your pointer after deleting it.
  3. 당신이 다른 사람의 코드를 잡아 경우, 아무도 저작권 통지를 변수 이름을 변경하지 않고 삭제하는 것이 기억, 누군가가 규칙 1 허용하지 않습니다 경우 규칙 1.

를 사용하지 것이다 어디에서나 작동하지 마십시오 이제까지 알아 차릴 것이다. 학교 프로젝트가 아니라면, 그들은 꽤 정교한 도구로 그런 종류의 속임수를 실제로 확인합니다. 참조 : this question.

+0

-1을 사용합니다. 나는 여기서 그것을 논하지 않겠지 만 그것은 ** 좋은 연습이 아니다. 코드가 꽤 잘 작성 되었다면, 더 이상 ** 다른 ** 참조/할당 된 메모리 블록에 대한 포인터가 없다는 것을 확신하기 전에 삭제해서는 안되기 때문에, 필요하지 않아야합니다. –

0
  • 수동으로 관리 메모리 를 사용할 수있을 때, 당신은 예를 들어, 사상 처음으로 적용 같은 범위/기능/클래스/모듈에 을 삭제 전화 확인 :
  • 가의 발신자를 보자 함수가 채워진 메모리를 할당하면 은 new'ed 포인터를 반환하지 않습니다.
  • 새로 호출 한 것과 동일한 exe/dll에서 항상 delete를 호출하십시오. 그렇지 않으면 힙 손상 (서로 다른 호환되지 않는 런타임 라이브러리)에 문제가있을 수 있습니다.
2

일반적인 경우 (자원 관리, 리소스가 반드시 메모리가 아닌 경우) RAII pattern에 익숙해야합니다.이것은 C++ 개발자에게 가장 중요한 정보 중 하나입니다.

0

당신은 기능과 같은 스마트 포인터를 구현하는 몇 가지 기본 클래스에서 모든 파생 수 (REF()/unref() 메소드와 카운터를 사용. @Timbo에 의해 강조

모든 포인트는 중요한 그 기본 클래스를 설계 할 때.

1

G'day,

내가 읽고 스콧 마이어스. 쉬운으로 "효과적인 C++"의 관련 섹션을 읽는 게 좋을 것 그가 부주의 함정에 몇 가지 흥미로운 개는 설명합니다.

난 또한 흥미가있는 템플릿 부족으로. 따라서 STL 또는 부스트는 없습니다. 와우.

동의어 사람들에게 협약에 동의하게하는 것은 좋은 생각입니다. 마찬가지로 모든 사람이 OOD 규칙에 동의하게됩니다. BTW Effective C++의 최신판에는 초판본이 유감 인 OOD 협약에 대한 훌륭한 장이 없습니다. 공용 가상 상속과 같은 규칙 항상 모델은 "isa"관계입니다.

3

내가 여기에 또 다른 규칙을 추가합니다 :

  • 은 새로운 것이 아니다를 수행을/자동 객체가 잘 할 것 객체를 삭제합니다.

우리는 C++를 처음 프로그래머 또는 프로그래머가 자바와 같은 언어에서 오는 것으로 나타났습니다은 새에 대해 배울 것하고 관계없이 문맥의 모든 객체를 생성 할 때마다 다음 강박을 사용합니다. 이것은 객체가 유용한 기능을 수행하는 함수 내에서 로컬로 생성 될 때 특히 유해합니다. 이 방법으로 new를 사용하면 성능에 해로울 수 있으며 해당 삭제를 잊어 버렸을 때 바보 같은 메모리 누수가 너무 쉽게 발생할 수 있습니다. 그렇습니다. 스마트 포인터는 후자를 도울 수 있지만 성능 문제를 해결하지는 못합니다 (새롭거나 삭제 된 것 또는 그와 동등한 것이 뒤에서 사용된다고 가정). 흥미롭게도 (어쩌면, 어쩌면) 우리는 삭제가 종종 Visual C++를 사용할 때 새로운 것보다 비싸지는 경향이 있다는 것을 발견했습니다.

이 혼란 중 일부는 포인터가 인수 (또는 스마트 포인터)를 인수로 취할 수도 있음을 알 수 있습니다 (참조가 더 좋거나 더 명확 할 때). 이것은 포인터를 함수에 전달할 수 있도록 포인터를 "만들어야"한다고 생각하게 만듭니다 (많은 사람들이 이것이 새로운 기능이라고 생각하는 것 같습니다). 이것은 분명히 함수 프로토 타입과 함께 제공되는 명확한 주석으로 강화 된 호출 규칙을 가능한 명확하게하기 위해 API를 작성하는 방법에 대한 몇 가지 규칙을 필요로합니다.

+0

니스에서 픽업하기 "이것은 그들이 필요하다고 생각하게 만듭니다 함수를 가리키는 포인터를 전달할 수 있도록 포인터를 "만들"(많은 사람들이 이것이 새로운 기능이라고 생각하는 것 같습니다)) "어쩌면, 대부분의 대학이 자바를 먼저 가르치기 때문에 그럴 것이라고 생각합니다. 자바에서는 모든 것을"새롭게 "해야합니다. 습관을 깨뜨리는 것은 어렵습니다. 특히 두 언어가 비슷해 보이지만 실제로는 완전히 다릅니다. 재미, 양쪽 모두 동시에 작업을 시도하십시오! –

2

일반적으로 힙에서 할당하지 마십시오. 필요한 경우 수명이 오래 걸리고 코드의 다양한 부분에서 공유해야하는 객체에 대한 참조 계산을 사용하십시오.

경우에 따라 개체를 동적으로 할당해야하지만 일정 기간 내에 만 개체가 사용됩니다. 예를 들어, 이전 프로젝트에서 나는 데이터베이스 스키마의 복잡한 메모리 내 표현 (기본적으로 객체의 복잡한 순환 그래프)을 작성해야했습니다. 그러나 그래프는 데이터베이스 연결 기간 동안 만 필요했으며 그 후에 모든 노드를 한 번에 해제 할 수있었습니다. 이런 종류의 시나리오에서 사용할 좋은 패턴은 "로컬 GC 관용구 (local GC idiom)"입니다. "공식"이름이 있는지 확실하지 않습니다. 내 코드와 코코아에서만 볼 수있는 것이기 때문입니다 (애플의 코코아 참조 NSAutoreleasePool 참조).

간단히 말해, new를 사용하여 할당 한 임시 개체에 대한 포인터를 유지하는 "수집기"개체를 만듭니다. 일반적으로 프로그램의 일부 범위, 정적 범위 (예 : RAII 관용구를 구현하는 스택에 할당 된 객체) 또는 동적 범위 (예 : 데이터베이스 연결 수명과 연결됨 내 이전 프로젝트). "collector"객체가 해제되면 소멸자는 자신이 가리키는 모든 객체를 해제합니다.

또한 DrPizza와 마찬가지로 템플릿을 사용하지 않는 제한은 너무 가혹합니다. 그러나 솔라리스, AIX 및 HP-UX의 고대 버전에 대한 많은 개발 작업을 수행 한 결과 (최근에는 Fortune 50에서 이러한 플랫폼이 계속 사용되고 있습니다), 이식성에 대해 정말로 염려한다면 가능한 한 템플릿을 거의 사용하지 않아야합니다. 컨테이너와 똑똑한 포인터를 위해 사용하는 것은 괜찮습니다. (그것은 저에게 효과적이었습니다). 템플리트가 없다면 필자가 설명한 기술은 구현하기가 더 어렵습니다. "콜렉터"가 관리하는 모든 오브젝트는 공통 기본 클래스에서 파생되어야합니다.

+0

로컬 GC 관용구 좋은 소리, 그것은 필요하지 않습니다. 수동 메모리 관리가 그렇게 잘 열심히하지 않습니다. –