是否有一种简洁,通用的方法来转换常规/哑指针的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> ]
答案 0 :(得分: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()
- 但这远非保证。
答案 1 :(得分: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();
}
答案 2 :(得分:7)
根据the documentation of Boost shared_ptr
,shared_ptr
构造函数标记为explicit
,这意味着没有从T*
到shared_ptr<T>
的隐式转换。因此,当您尝试将定义旧容器的迭代器范围插入到新容器中时,编译器会抱怨,因为无法将旧容器的原始指针隐式转换为新容器的shared_ptr
。容器。您可以通过使用back_inserter
和transform
来解决此问题,或者通过手动迭代来包装每个指针并一次插入一个。
事实证明,您不希望此转换隐式工作。考虑:
void DoSomething(shared_ptr<T> ptr) {
/* ... */
}
T* ptr = new T();
DoSomething(ptr);
如果此处允许隐式转换,则对DoSomething
的调用将是合法的。但是,这会导致新的shared_ptr
开始引用ptr
所持有的资源。这是有问题的,因为当shared_ptr
返回时此DoSomething
超出范围时,它将看到它是资源的唯一shared_ptr
并将取消分配它。换句话说,使用原始指针调用DoSomething
会隐式删除指针!
答案 3 :(得分:3)
仅仅因为你说for instance, boost::shared_ptr
- 如果语义适合你,那么boost::ptr_vector
存储一个指针向量,当向量超出范围时负责释放它们。这个容器有一个transfer
方法,你可以用它来获取你得到的向量中包含的指针的所有权。
答案 4 :(得分:1)
只需使用范围构造函数:
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;
};
这使得处理多态类型的容器变得更加容易!