簡體   English   中英

將指針容器轉換為智能指針?

[英]Convert container of pointers to smart pointers?

是否有一種簡潔,通用的方法來轉換常規/啞指針的std容器(如vector ):

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() );

但那拒絕編譯(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>        ]

你可以使用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()強調這vec_a.clear() - 但這遠非保證。

::std::back_inserter::std::transform以及一個將執行轉換的小函數。 如果你也使用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();
}

根據Boost shared_ptr的文檔shared_ptr構造函數被標記為explicit ,這意味着沒有從T* s到shared_ptr<T>隱式轉換。 因此,當您嘗試將定義舊容器的迭代器范圍插入到新容器中時,編譯器會抱怨,因為無法從舊容器的原始指針隱式轉換為新容器的shared_ptr 您可以通過使用back_insertertransform ,或者通過手動迭代來包裝每個指針並一次插入一個來解決此問題。

事實證明,你有一個很好的理由不希望這種轉換隱含地發揮作用。 考慮:

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

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

如果允許隱式轉換,則調用DoSomething將是合法的。 但是,這會導致新的shared_ptr開始引用ptr所持有的資源。 這是有問題的,因為當DoSomething返回時,當shared_ptr超出范圍時,它將看到它是資源的唯一shared_ptr並將解除分配它。 換句話說,使用原始指針調用DoSomething將隱式刪除指針!

正因為你所說的for instance, boost::shared_ptr - 如果語義適合你,有boost::ptr_vector存儲一個指針向量,並負責在向量超出范圍時釋放它們。 這個容器有一個transfer方法,你可以使用它來獲取你得到的向量中包含的指針的所有權。

只需使用范圍構造函數,如下所示:

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

從概念上講,它相當於:

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;
};

這使得處理多態類型的容器變得更加容易!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM