将指针容器转换为智能指针?

gen*_*ult 3 c++ boost pointers stl smart-pointers

是否有一种简洁,通用的方法来转换常规/哑指针的std容器(如vector):

vector< T* >
Run Code Online (Sandbox Code Playgroud)

例如,boost::shared_ptr?:

vector< boost::shared_ptr<T> >
Run Code Online (Sandbox Code Playgroud)

我以为我可以使用vector范围构造函数将其拉出来:

vector< T* > vec_a;
...
vector< boost::shared_ptr<T> > vec_b( vec_a.begin(), vec_a.end() );
Run Code Online (Sandbox Code Playgroud)

但那拒绝编译(Visual Studio 2008).

编辑:测试代码:

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

编译错误:

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>        ]
Run Code Online (Sandbox Code Playgroud)

pet*_*hen 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);
Run Code Online (Sandbox Code Playgroud)

但是,建议的做法是在创建后立即为智能指针分配原始指针.将原始指针放入容器中,然后将它们复制到另一个容器看起来很危险.你需要确保没有其他人能够释放这些原始指针.您可以vec_a.clear()在转移后立即强调- 但这远非保证.


Omn*_*ous 7

结合::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();
}
Run Code Online (Sandbox Code Playgroud)


tem*_*def 7

根据Boost的文档shared_ptr,shared_ptr构造函数被标记explicit,意味着没有从T*s到p的隐式转换shared_ptr<T>.因此,当您尝试将定义旧容器的迭代器范围插入到新容器中时,编译器会抱怨,因为无法从旧容器的原始指针隐式转换shared_ptr为新容器的s.您可以通过使用back_insertertransform,或者通过手动迭代来包装每个指针并一次插入一个来解决此问题.

事实证明,你有一个很好的理由不希望这种转换隐含地发挥作用.考虑:

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

T* ptr = new T();
DoSomething(ptr);
Run Code Online (Sandbox Code Playgroud)

如果此处允许隐式转换,那么调用DoSomething将是合法的.但是,这会导致new shared_ptr开始引用所持有的资源ptr.这是有问题的,因为当返回时shared_ptr超出范围时DoSomething,它将看到它是唯一shared_ptr的资源并将解除分配它.换句话说,DoSomething使用原始指针调用将隐式删除指针!