2010-11-23 2 views
1

성능에 중요한 코드가 있습니다. 클래스와 객체는 상당히 크기 때문에 STL 컨테이너에 포인터로 저장됩니다. 개체에 대한 포인터를 일부 논리에 따라 여러 컨테이너에 저장해야하는 경우 문제가 발생합니다. 개체의 소유권을 단일 컨테이너 (단일 컨테이너에서 삭제할 수 있음)로 격리 할 수 ​​없기 때문에 개체의 소유권을 처리하는 것은 매우 지저분합니다. 스마트 포인터를 사용하는 것 (성능에 치명적이며 스마트 포인터가 성능에 영향을 줄 수 있기 때문에) 이외에 무엇을 할 수 있습니까?C++에서 원시 포인터 관리

감사합니다.

+7

스마트 포인터를 사용해보십시오. 너무 많은 영향을 미치는지 확인하는 프로필. 기회는 너무 많지 않을 것이며, 대부분의 자신 만의 솔루션보다 적을 것입니다. – sje397

+1

불행히도 할 수있는 일이별로 없습니다. 책임을 정의해야합니다. 즉 책임자는 리소스를 소유해야합니다. 제 견해로 이것은 C++의 근본적인 문제이며 사람들이 다른 언어로 옮겨가는 가장 큰 이유 중 하나 일 것입니다. –

+1

스마트 포인터를 프로파일 링 했습니까? 아니면 그냥 추측입니까? – Simone

답변

5

당신이 주장하는 똑똑한 포인터가 제공 할 수없는 뛰어난 성능을 원한다면 한 지점에서 안전과 깔끔함을 요구할 수도 있습니다. 글쎄요, 실제로는 다른 것을 희생해야합니다. 당신은 물론 자신의 공유 포인터를 작성하려고 할 수 있습니다. 공유 포인터는 부스트보다 가볍지 만 여전히 기본 기능을 제공합니다. 덧붙여 말하자면, 실제로 시도했습니다 boost :: shared_ptr? 실제로 성능이 저하 되었습니까?

+2

'shared_ptr'에 대한 한 가지 점 : make_shared를 사용하여 빌드하는 것이 가장 효율적입니다. –

+0

또한 뮤텍스 비용 지불을 피하기 위해 shared_ptr의 스레드 안전을 비활성화 할 수 있습니다. – Gianni

1

귀하의 질문은 매우 어색합니다 : 당신은 지저분한 논리로 성능을 요구합니까?

shared_ptr은 놀라운 성능을 제공합니다. 실제로 더 나은 결과를 얻을 수 있지만 최상의 선택입니다.

다른 부스트 스마트 포인터를 찾아 볼 수도 있습니다 : boost::intrusive_ptr.

이것은 앞에서 설명한 비용으로 수행됩니다 : weak_ptr 그리고 교환기에서는 카운터와 객체 모두에 대해 단일 메모리 할당을 허용합니다. 이 두 가지를 압축하면 성능이 약간 향상됩니다.

순환 참조가 없으면 확인하고 시도해보십시오. 찾고 있던 내용 일 수 있습니다.

+0

포장은 make_shared 기능으로도 가능합니다. – ronag

+0

@ronag :'make_shared'가 정확하게 기억하고 있다면'counter '는'shared_ptr' 풀과'weak_ptr' 풀 사이에서 공유되고 스스로 생명을 산다. 'make_shared' 팩은 deleter와 실제 할당 된 객체입니다. 나는 실수 할 수 있지만, 부스트 소스를 통해 터벅 터벅 걷는 것은 확실히 내가 좋아하는 과거의 시간은 아니다. –

0

침입 형 스마트 포인터는 일반적으로 일반 스마트 포인터보다 효율적이지만 벙어리 포인터보다 쉽습니다. 예를 들어, 체크 아웃 boost::intrusive_ptr<T>

+0

'make_shared'는 침입 포인터를 꽤 비난합니다 ... – fredoverflow

0

개체가 서로를 참조하지 않으면 수동 참조 카운팅을 시도해 볼 가치가 있습니다. 목록에 추가하거나 목록에서 제거 할 때 더 많은 비용이 들지만 실제 개체 액세스에는 오버 헤드가 없습니다. (잘못했을 때 진단하는 것은 고통 스러울 수 있으므로 올바르게 진행하는 것이 좋습니다.)

작업 사이에 불감 시간이 있으면 일종의 가비지 수집을 고려하십시오. 모든 객체의 목록을 유지 관리하십시오 (방해하지 않는 목록이 아마도 수행 할 것입니다). 시간을 할애 할 때 다른 목록과 교차 참조하십시오. 목록에없는 모든 개체는 삭제 될 수 있습니다. 이 작업을 수행하기 위해 여분의 배열 (각 개체의 전역 카운터 및 마지막 카운터)이 필요하지 않으므로 효율적입니다.

또 다른 옵션은 기본 포인터에 대한 액세스를 제공하는 스마트 포인터를 사용하는 것입니다. 과부하가 걸리는 오버 헤드를 피하려고한다면 operator->을 많이 사용하는 것이 좋습니다. 목록에 스마트 포인터를 저장하면 (수명 관리를 수행함) 객체를 실행할 때 각각의 원시 포인터를 검색하고이를 사용하여 작업 할 수 있습니다 (오버로드 된 오버 헤드가 발생하지 않도록 operator-> 등).). 예 :

std::vector<smart_ptr<T> > objects; 

if(!objects.empty()) { 
    smart_ptr<T> *objects_raw=&objects[0]; 
    for(size_t n=objects.size(),i=0;i<n;++i) { 
     T *object=objects_raw[i].get_ptr(); 

     // do stuff 
    } 
} 

이것은 개인적으로 선호하는 방식입니다.장기 저장은 스마트 포인터를 가져오고 단기 저장은 일반 포인터를 얻습니다. 객체 수명은 관리하기 쉽고, 1,000,000 개의 작은 오버 헤드가 발생하지 않습니다 (디버그 빌드를 릴리스 빌드보다 실행 가능한 상태로 유지하는 것이 중요하지만 그럼에도 불구하고 낭비되는 시간을 쉽게 추가 할 수 있습니다).

관련 문제