2010-12-08 6 views
0

내 질문에 내 인터페이스에서 boost :: shared_ptr을 사용하고 내 인터페이스에서 원시 포인터 또는 참조를 노출해야하는지 여부를 묻는 질문에 대한 답을 드리겠습니다.에 관한 혼란 boost :: shared_ptr

Employeer이있는 사람의 경우를 생각해 보자. 직원은 내부적으로 모든 직원을 vector< shared_ptr<Person> >에 유지합니다. 이 때문에, Person이 관련된 인터페이스는 shared_ptr 랩핑 된 사람이어야한다고 모범 사례에서 지시합니까?

예를 들어

, 모든 또는 만이 확인 중 일부 :

Person Employeer::getPresidentCopy(); 
Person& Employeer::getPresidentRef(); 
Person* Employeer::getPresidentRawPtr(); 
shared_ptr<Person> Employeer::getPresidentSharedPtr(); 

또는 예를 들어

:

void Employeer::hireByCopy(Person p); 
void Employeer::hireByRef(Person& p); 
void Employeer::hireByRawPtr(Person* p); 
void Employeer::hireBySharedPtr(shared_ptr<Person> p); 

나중에 대신 부스트 다양한 johns_very_own_shared_ptr 사용하도록 구현을 변경하려면 , 이전 구현에 갇혀 있습니까?

반면에 인터페이스에서 원시 포인터 또는 참조를 노출하는 경우 shared_ptr 아래에서 메모리를 삭제하는 사람이 있습니까? 아니면 shared_ptr이 삭제되어 내 참조가 무효화 될 위험이 있습니까?


예를 들어 내 new question을 참조하십시오.

답변

3

, 모든 또는 만이 확인 중 일부는 :

그것은 당신에 따라 달라집니다 성취하려고 노력하고있어. 값으로 Person을 직접 저장하는 대신 벡터가 shared_ptr 인 이유는 무엇입니까? (그리고 당신은 boost::ptr_vector으로 생각 했습니까?)

당신이 정말로 배부해야하는 것이 weak_ptr일지도 고려해야합니다.

나중에 부스트 버라이어티 대신 johns_very_own_shared_ptr을 사용하도록 구현을 변경하려면 이전 구현에서 트랩 되었습니까?

거의 수정이 불가능하지 않습니다. (나는 C++ 0x에서 0x34의 auto 키워드를 자유롭게 사용하면이 코드를 더 쉽게 처리 할 수 ​​있다고 생각합니다. typedef을 사용하지 않았더라도 호출 코드를 수정할 필요가 없기 때문입니다.) 그러나 그렇다면 왜 을 원하면을 원하십니까?

반면에 인터페이스에서 원시 포인터 또는 참조를 노출하는 경우 shared_ptr 아래에서 메모리를 삭제하는 사람이 있습니까?

네,하지만 그건 당신의 문제가 아닙니다. 사람들은 shared_ptrdelete에서 원시 포인터를 추출 할 수 있습니다. 그러나 불필요하게 안전하지 않은 것들을 피하려면 여기에 원시 포인터를 반환하지 마십시오.아무도 인데 아무 것도 말하지 않으므로delete &reference_received_from_api;이라고하는 사람이 없으므로 참조가 훨씬 좋습니다. (희망 이니까, 어쨌든 ^^ ;;;)

+0

Employeer 예제는 당시 내가 제시 할 수있는 최상의 예였습니다. shared_ptrs를 사용하는 실제 클래스에는 실제로 해당 기능이 필요합니다. 감사! – JnBrymn

+0

아, 나는 당신이 그 기능을 필요로한다고 당신을 믿는다; 왜 다른 이유가있을 수 있습니다, 그리고 당신이 다른 디자인 결정을 내릴 때 고려해야합니다 :) –

2

shared_ptr을 전달할 필요는 없지만 원시 포인터를 전달하면 객체가 소멸 된 후 일부 원시 포인터가 지속될 위험이 있습니다.

치명적인 결과가 발생합니다.

그래서 일반적으로 참조를 넘겨 주면 (클라이언트 코드가 주소를 사용하면 클라이언트 코드가 * shared_ptr의 주소를 취하는 것보다 더 이상 오류가 발생하지 않음) 원시 포인터가 가장 먼저 생각합니다.

건배 & HTH.,

+0

고마워, 고마워. 일반적으로 참조의 주소를 가져서는 안된다는 것이 일반적으로 인정됩니까? 아니면 그 말을 해설해야합니까? – JnBrymn

2

당신이 shared_ptr의를 사용할 때 내가, 사용자 원시 포인터를 제공해서는 안된다. 사용자가 삭제할 수 있습니다. 중복 삭제의 원인은 무엇입니까?

boost:shared_ptr의 사용을 숨기려면 typedef을 사용하여 실제 유형을 숨기고이 새로운 유형을 대신 사용할 수 있습니다.

typedef boost::shared_ptr<Person> Person_sptr; 
+0

더 좋은 조언. – JnBrymn

+1

@Alf가 지적했듯이,'shared_ptr'이나 참조를 넘겨주는 것은 객체 인스턴스의 범죄적인 오용에 대한 만병 통치약이 아닙니다. 'shared_ptr'과 raw 포인터를 선호하는 이유로써 객체의 보호를 인용하면 오도 된 것이다. –

+0

네 말이 맞지만, 실수를 막기에 충분하다. 사용자는 단지'delete e123.getPresidentSharedPtr();'을 할 수 없습니다. 나는 사용자가 애플리케이션을 망치고 싶어한다고 가정하지 않는다, 나는 그가 실수로 이것을 할 수 있다고 가정한다. –

3

나는 typedef을 소개하고 변경 사항으로부터 보호합니다. 이런 식으로 뭔가 :

typedef std::shared_ptr<Person> PersonPtr; 

PersonPtr Employeer::getPresident() const; 

나는 앞으로 선언과 함께 헤더 A (한)에서 이와 같은 형식 정의를 배치합니다. 이렇게하면 내가 원한다면 쉽게 바꿀 수 있습니다.

1

여기에 shared_ptr을 전달하는 유일한 이유는 반환 된 객체 참조의 유효 기간이 벡터의 거주 기간에 직접적으로 연결되지 않은 경우입니다.

누군가가 Employee이 중지 된 후 Person에 액세스 할 수있게하려면 shared_ptr이 적합 할 것입니다.다른 Employer에 대해 Personvector으로 이동한다고 가정 해보십시오.

+0

Employeer 예제는 당시 내가 제시 할 수있는 최상의 예였습니다. shared_ptrs를 사용하는 실제 클래스에는 실제로 해당 기능이 필요합니다. 하지만 고마워. – JnBrymn

+0

@ 존 - 좋은 점은 결정은 컨테이너 객체를 방화벽으로 막는 것이 아니라'Person' 객체 수명의 의미에 관한 것입니다. 컨테이너에서 객체를 방화벽으로 보호하는 유일한 방법은 사본을 전달하는 것입니다. –

0

여러 라이브러리를 연결하는 적당한 크기의 프로젝트에서 작업합니다. 이러한 라이브러리 중 일부는 자체 메모리 관리 하위 시스템 (APR, MFC)을 가지고 있으며 실제로 나를 귀찮게합니다. 세계에 대한 그들의 견해가 좋든 나쁘 든, 그것은 다른 모든 사람들과 완전히 다르며 그렇지 않은 경우보다 조금 더 많은 코드가 필요합니다.

또한, 해당 라이브러리는 malloc 또는 newjemalloc로 또는 Boehm-Demers-Weiser garbage collector 더 힘들어 (on Windows it's already hard enough)를 스와핑합니다.

나는 내 자신의 코드에서 공유 포인터를 많이 사용하지만 다른 사람들에게 메모리를 관리하는 방법을 선호하지 않습니다. 대신, 객체 가능한 (라이브러리 사용자가 결정시키는 언제 어떻게 메모리를 할당하는 방법), 그것이 불가능하면 중 하나를 수행 나누어 :

  1. 손 밖으로 원시 포인터 (플러스 약속 중 하나를 그 포인터 수 delete D 또는 Destroy() 기능은 newstd::allocator)
  2. 기본값 주시기 바랍니다 (메모리 관리를 위해 사용하는 어떤 사용자에 연결할 수 있도록
  3. 함수 또는 STL 할당과 같은 주장을 받아) 개체를 할당 해제 호출 할 수
  4. 라이브러리 사용자가 메모리 버퍼를 할당 받도록하십시오 (like std::vectors)

불쾌한 일 필요는 없습니다 라이브러리의이 종류를 사용 : 예를 들어

// situation (1) from above 
std::shared_ptr<Foo> foo(Library_factory::get_Foo(), Library_factory::deallocate); 

// situation (2) above (declaration on next line is in a header file) 
template<typename allocator=std::allocator<Foo> > Foo* library_function_call(); 
boost::shared_ptr<Foo> foo = library_function_call(); 

// situation (3) above, need to fill a buffer of ten objects 
std::vector<Foo> foo_buffer(10); 
fill_buffer(&foo_buffer[0], foo_buffer.size()); 
관련 문제