2011-01-24 3 views
3

(예 : vector 등)/일반 벙어리 포인터의 std 컨테이너를 변환하는 간결하고 일반적인 방법이 있나요 :포인터의 컨테이너를 스마트 포인터로 변환 하시겠습니까?

vector< T* > 

에, 예를 들어, boost::shared_ptr :

vector< boost::shared_ptr<T> > 

가 내가 생각 vector의 범위 생성자를 사용하여 해낼 수 :

vector< T* > vec_a; 
... 
vector< boost::shared_ptr<T> > vec_b(vec_a.begin(), vec_a.end()); 

을하지만 COM에 거부 더미 (Visual Studio 2008).

편집 : 테스트 코드 :

void test() 
{ 
vector< int* > vec_a; 
vector< boost::shared_ptr<int> > vec_b(vec_a.begin(), vec_a.end()); 
} 

컴파일 오류 :

1>c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\memory(131) : error C2664: 'std::allocator<_Ty>::construct' : cannot convert parameter 2 from 'int *' to 'const boost::shared_ptr<T> &' 
1>  with 
1>  [ 
1>   _Ty=boost::shared_ptr<int> 
1>  ] 
1>  and 
1>  [ 
1>   T=int 
1>  ] 
1>  Reason: cannot convert from 'int *' to 'const boost::shared_ptr<T>' 
1>  with 
1>  [ 
1>   T=int 
1>  ] 
1>  Constructor for class 'boost::shared_ptr<T>' is declared 'explicit' 
1>  with 
1>  [ 
1>   T=int 
1>  ] 
1>  c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\memory(822) : see reference to function template instantiation '_FwdIt std::_Uninit_copy<int**,_FwdIt,_Alloc>(_InIt,_InIt,_FwdIt,_Alloc &,std::_Nonscalar_ptr_iterator_tag,std::_Range_checked_iterator_tag)' being compiled 
1>  with 
1>  [ 
1>   _FwdIt=boost::shared_ptr<int> *, 
1>   _Alloc=std::allocator<boost::shared_ptr<int>>, 
1>   _InIt=int ** 
1>  ] 
1>  c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\vector(1141) : see reference to function template instantiation '_FwdIt stdext::unchecked_uninitialized_copy<_Iter,boost::shared_ptr<T>*,std::allocator<_Ty>>(_InIt,_InIt,_FwdIt,_Alloc &)' being compiled 
1>  with 
1>  [ 
1>   _FwdIt=boost::shared_ptr<int> *, 
1>   _Iter=std::_Vector_iterator<int *,std::allocator<int *>>, 
1>   T=int, 
1>   _Ty=boost::shared_ptr<int>, 
1>   _InIt=std::_Vector_iterator<int *,std::allocator<int *>>, 
1>   _Alloc=std::allocator<boost::shared_ptr<int>> 
1>  ] 
1>  c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\vector(956) : see reference to function template instantiation 'boost::shared_ptr<T> *std::vector<_Ty>::_Ucopy<_Iter>(_Iter,_Iter,boost::shared_ptr<T> *)' being compiled 
1>  with 
1>  [ 
1>   T=int, 
1>   _Ty=boost::shared_ptr<int>, 
1>   _Iter=std::_Vector_iterator<int *,std::allocator<int *>> 
1>  ] 
1>  c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\vector(889) : see reference to function template instantiation 'void std::vector<_Ty>::_Insert<_Iter>(std::_Vector_const_iterator<_Ty,_Alloc>,_Iter,_Iter,std::forward_iterator_tag)' being compiled 
1>  with 
1>  [ 
1>   _Ty=boost::shared_ptr<int>, 
1>   _Iter=std::_Vector_iterator<int *,std::allocator<int *>>, 
1>   _Alloc=std::allocator<boost::shared_ptr<int>> 
1>  ] 
1>  c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\vector(537) : see reference to function template instantiation 'void std::vector<_Ty>::insert<_Iter>(std::_Vector_const_iterator<_Ty,_Alloc>,_Iter,_Iter)' being compiled 
1>  with 
1>  [ 
1>   _Ty=boost::shared_ptr<int>, 
1>   _Iter=std::_Vector_iterator<int *,std::allocator<int *>>, 
1>   _Alloc=std::allocator<boost::shared_ptr<int>> 
1>  ] 
1>  c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\vector(514) : see reference to function template instantiation 'void std::vector<_Ty>::_Construct<_Iter>(_Iter,_Iter,std::input_iterator_tag)' being compiled 
1>  with 
1>  [ 
1>   _Ty=boost::shared_ptr<int>, 
1>   _Iter=std::_Vector_iterator<int *,std::allocator<int *>> 
1>  ] 
1>  .\test.cpp(8364) : see reference to function template instantiation 'std::vector<_Ty>::vector<std::_Vector_iterator<int,_Alloc>>(_Iter,_Iter)' being compiled 
1>  with 
1>  [ 
1>   _Ty=boost::shared_ptr<int>, 
1>   _Alloc=std::allocator<int *>, 
1>   _Iter=std::_Vector_iterator<int *,std::allocator<int *>> 
1>  ] 
+0

VS2008에서 어떤 오류가 발생 했습니까? – templatetypedef

+2

@templatetypedef : boost :: shared_ptr은 원시 포인터에서 암시 적으로 생성을 허용하지 않으므로 (컴파일러는 의미 변경을 숨길 수 있기 때문에) 컴파일러는 관련없는 유형을 고려합니다. – peterchen

+0

@templatetypedef : 테스트 스텁 및 오류 추가 – genpfault

답변

7

::std::transform 및 변환을 수행 할 약간의 기능을 ::std::back_inserter를 결합합니다. reserve도 사용하는 경우 상당히 효율적입니다.

template <class T> 
static inline ::std::tr1::shared_ptr<T> to_shared_ptr(T *val) 
{ 
    return ::std::tr1::shared_ptr<T>(val); 
} 

void test() 
{ 
    ::std::vector< int* > vec_a; 
    ::std::vector< ::std::tr1::shared_ptr<int> > vec_b; 
    vec_b.reserve(vec_a.size()); 
    ::std::transform(vec_a.begin(), vec_a.end(), ::std::back_inserter(vec_b), 
        to_shared_ptr<int>); 
    vec_a.clear(); 
} 
+0

ITYM'return :: std :: tr1 :: shared_ptr (val); ' –

+0

@ 스티브 제섭 : 고마워! – Omnifarious

9

당신은 사용할 수 std::transform :

그러나
template <typename T> 
    boost::shared_ptr<T> to_shared_ptr(T * p) { return boost::shared_ptr<T>(p); } 

    vec_b.resize(vec_a.size()); 
    std::transform(vec_a.begin(), vec_a.ebd(), vec_b.begin(), to_shared_ptr); 

, 권장 연습을 즉시 생성 한 후 스마트 포인터에 원시 포인터를 지정하는 것입니다 모든 템플릿이 확장되면 당신은 기본적으로이 코드를 얻을 것이다 . 원시 포인터를 컨테이너에 넣은 다음 다른 컨테이너에 복사하면 위험 해 보입니다. 당신은 아무도 이러한 원시 포인터를 해제하지 않도록해야합니다. 전송 후 즉시 vec_a.clear()까지 강조 할 수 있습니다. 그러나 이것은 보장과는 거리가 .니 다.

+0

참조로 전달 된 '벡터 '에 추가하려는 기존 API로 작업하고 있습니다. 그것을 조금 더 안전하게 사용하기를 바랬습니다. – genpfault

+0

스마트 포인터가 메모리를 해제 한 후에 아무도 원시 포인터를 사용하지 않도록하여 재미있게 추가해야합니다. –

+0

@genpfault : 합법적 인 이유가 있다고 생각합니다. 기존 API에 "완료 한 후에 삭제해야하며 다시는 볼 수 없습니다"라고 표시되면 문제가되지 않습니다. – peterchen

7

the documentation of Boost shared_ptr에 따르면, shared_ptr 생성자는 T*의에서 shared_ptr<T>에는 암시 적 변환이 없다는 것을 의미 explicit을 표시됩니다. 결과적으로 이전 컨테이너를 정의하는 반복기 범위를 새 컨테이너에 삽입하려고하면 컴파일러는 이전 컨테이너의 원시 포인터에서 새 컨테이너의 shared_ptr으로 암시 적으로 변환 할 방법이 없기 때문에 불평합니다. back_insertertransform을 사용하거나 각 포인터를 줄 바꿈하여 한 번에 하나씩 삽입하여 반복적으로 수정하면됩니다.

이 변환이 암시 적으로 작동하지 않기를 바랄만한 이유가 있습니다. 고려 : 암시 적 변환이 여기에 허용 된 경우

void DoSomething(shared_ptr<T> ptr) { 
    /* ... */ 
} 

T* ptr = new T(); 
DoSomething(ptr); 

, 다음 DoSomething에 대한 호출이 법적 될 것이다. 그러나이 경우 은 ptr이 보유한 리소스를 참조하기 시작합니다. DoSomething이 반환 될 때이 shared_ptr이 범위를 벗어나면 리소스에 대한 유일한 shared_ptr이며 할당을 해제하므로이 문제가 발생합니다. 즉, 원시 포인터로 DoSomething을 호출하면 암시 적으로 포인터가 삭제됩니다!

3

for instance, boost::shared_ptr - 의미가 맞는 경우 boost::ptr_vector은 포인터 벡터를 저장하며 벡터가 범위를 벗어날 때 해제하는 역할을합니다. 이 컨테이너에는 얻은 벡터에서 cointained 된 포인터의 소유권을 가져올 수있는 transfer 메서드가 있습니다.

for (int num : nums) 
    smart_nums.emplace_back(num); 

이제 범위 생성자와 다음이 가능 :

class Num_container { 
public: 
    Num_container(vector<int*> nums) 
     : smart_nums(nums.begin(), nums.end()) { } 
private: 
    vector<shared_ptr<int>> smart_nums; 
}; 

개념적으로는 동등하다

vector<int*> nums = { new int(1), new int(5), new int(10) }; 
vector<shared_ptr<int>> smart_nums(nums.begin(), nums.end()); 

:

1

그냥 범위 생성자과 같이 사용 이것은 다형성 타입의 컨테이너를 다루는 것을 훨씬 쉽게 만든다!

관련 문제