2009-02-26 12 views
2

메모리 관리에 관한 몇 가지 질문 (herehere)을 요청했으며 누군가 boost :: shared_ptrs를 사용한다고 제안합니다.Boost :: shared_ptrs를 사용하지 않는 이유가 있습니까?

그들이 얼마나 유용한 지 감안할 때, 나는 boost :: shared_ptrs를 사용하도록 내 전체 응용 프로그램을 전환하는 것을 진지하게 고려하고있다.

그러나 두 발로 뛰어 들어이 작업을 수행하기 전에 나는 부탁하고 싶다. - 누군가 boost :: shared_ptrs에 나쁜 경험을 했습니까? 내가 조심할 필요가있는 것들을 사용하는 데 몇 가지 함정이 있습니까?

지금은 거의 사실이 아닌 것 같아요. 자동으로 대부분의 가비지 수집 문제를 처리합니다. 단점은 무엇입니까?

답변

4

단점은 자유롭지 않다는 점입니다. scoped_ptr/scoped_array (또는 일반 오래된 스택 할당)이 수행 할 경우 특히 shared_ptr/shared_array을 사용하지 않아야합니다. 있을 경우 수동으로주기를 weak_ptr으로 중단해야합니다. 링크 된 벡터 질문은 shared_ptr에 도달 할 수있는 한 가지 경우입니다. 두 번째 질문은 그렇지 않습니다. 복사하지 않는 것은 조기 최적화입니다. 특히 문자열 클래스가 이미이를 처리하는 경우 특히 그렇습니다. 문자열 클래스가 참조 카운트 된 경우 COW를 제대로 구현할 수있게되며 shared_ptr<string> 접근 방식으로는 실제로 수행 할 수 없습니다. shared_ptr willy-nilly를 사용하면 외부 라이브러리/api와 "인터페이스 마찰"을 도입 할 수 있습니다.

+0

문자열은 일반적으로 COW를 사용하지 않습니다. 다중 스레드 응용 프로그램에서는 잘 작동하지 않으므로 대부분의 구현에서 다시 스레드를 제거합니다. 이는 문자열 사본이 다소 비싸다는 것을 의미합니다. – jalf

+0

GCC의 문자열 구현은 여전히 ​​COW IIRC를 사용합니다. 그러나 C++ 0x의 경우에는 허용되지 않을 가능성이 있습니다 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2668.htm). –

0

동적 메모리 오버 헤드 (즉, 여분의 할당) + 참조 카운트 된 스마트 포인터와 관련된 모든 오버 헤드.

2

C++에서 공유 포인터 또는 다른 메모리 관리 기법을 사용하는 것이 만병 통치약이 아닙니다. 신중한 코딩을 대체 할 수는 없습니다. boost :: shared_ptr을 사용하여 객체 소유권을 인식하고 순환 참조를 피하십시오. 명시 적으로 사이클을 중단하거나 필요할 경우 boost :: weak_ptr을 사용해야합니다.

할당 된 순간부터 인스턴스에 항상 boost :: shared_ptr을 사용하도록주의하십시오. 그런 식으로 당신은 매달린 참조를 가지지 않을 것이라고 확신합니다. 한 가지 방법은 새로 생성 된 객체를 반환하는 팩토리 메소드를 shared_ptr에 사용하는 것입니다.

typedef boost::shared_ptr<Widget> WidgetPtr; 
WidgetPtr myWidget = Widget::Create(); 
1

자주 shared_ptr을 사용합니다.

Shared_ptr는 값에 의해 복사되므로 포인터 값과 참조 횟수를 모두 복사하는 데 드는 비용이 발생할 수 있지만 boost :: intrusive_ptr을 사용하면 참조 횟수를 클래스에 추가해야합니다. 원시 포인터를 사용하는 것 이상의 추가 오버 헤드가 없습니다.

그러나 내 경험상 99 % 이상의 시간 동안 코드 전체에 boost :: shared_ptr 인스턴스를 복사하는 오버 헤드가 중요하지 않습니다. 일반적으로 C. A. R. Hoare가 지적했듯이 조기 최적화는 무의미합니다. 대부분 다른 코드는 작은 객체를 복사하는 데 걸리는 시간보다 훨씬 더 많은 시간을 사용합니다. 귀하의 마일리지가 다를 수 있습니다. 프로파일 링에 문제가 있다는 것을 보여주는 프로파일 링이라면, 침입 형 포인터로 전환 할 수 있습니다.

위에서 설명한 것처럼 weak_ptr을 사용하여 순환을 중단해야하며 그렇지 않으면 메모리 누수가 발생합니다. 이것은 일부 그래프와 같은 데이터 구조에서 발생하지만, 예를 들어 리프가 결코 뒤를 향하지 않는 트리 구조를 만들고 있다면 문제없이 트리의 노드에 대해 shared_pointers를 사용할 수 있습니다.

shared_ptr을 사용하면 코드가 크게 단순 해져 읽고 읽기가 쉬워지고 유지 관리가 쉬워집니다. 많은 경우에이를 사용하는 것이 올바른 선택입니다.

물론 앞에서 언급했듯이 scoped_ptr (또는 scoped_array)을 사용하는 것이 올바른 선택입니다. pointee가 공유되지 않으면 공유 포인터를 사용하지 마십시오!

마지막으로 가장 최근의 C++ 표준은 st1 :: tr1 :: shared_ptr 템플릿을 제공합니다.이 템플릿은 tr1에 대한 방해가되는 포인터 유형이 있다고 생각하지는 않지만 대부분의 플랫폼에 있습니다 (또는 오히려 , 그러나 나는 그것의 자신을 듣지 않았다).

관련 문제