将指针容器转换为智能指针?
是否有一种简洁、通用的方法来将常规/哑指针的 std
容器(例如 vector
)转换
vector< T* >
为例如 boost::shared_ptr< /code>?:
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> ]
Is there a concise, generic way to convert a std
container (such as vector
) of regular/dumb pointers:
vector< T* >
to, for instance, boost::shared_ptr
?:
vector< boost::shared_ptr<T> >
I thought I could pull it off using vector
's range constructor:
vector< T* > vec_a;
...
vector< boost::shared_ptr<T> > vec_b( vec_a.begin(), vec_a.end() );
but that refused to compile (Visual Studio 2008).
EDIT: Test code:
void test()
{
vector< int* > vec_a;
vector< boost::shared_ptr<int> > vec_b( vec_a.begin(), vec_a.end() );
}
Compilation errors:
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> ]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您可以使用 std::transform:
但是,建议的做法是在创建后立即将原始指针分配给智能指针。将原始指针放入容器中,然后将它们复制到另一个容器中看起来很危险。您需要确保没有其他人释放这些原始指针。您可以在传输后立即通过 vec_a.clear() 来强调这一点 - 但这远非保证。
You could use
std::transform
:However, the recommended practice is to assign raw pointers to smart pointers immediately after creation. Having the raw pointers put in a container, then copying them to another another container looks dangerous. YOu need to make sure noone else ever frees these raw pointers. You could emphasize that by
vec_a.clear()
immediately after the transfer - but that's far from a guarantee.将
::std::back_inserter
与::std::transform
和一个执行转换的小函数结合起来。如果您还使用reserve
,这应该相当有效。展开所有模板后,您基本上会得到以下代码:Combine
::std::back_inserter
with::std::transform
and a little function that will perform the conversion. If you also usereserve
, this should be reasonably efficient. Once all the templates are expanded you will essentially get this code:根据 Boost
shared_ptr
的文档< /a>,shared_ptr
构造函数被标记为显式
,这意味着没有从T*
到shared_ptr的隐式转换。
。因此,当您尝试将定义旧容器的迭代器范围插入新容器时,编译器会发出警告,因为无法从旧容器的原始指针隐式转换为shared_ptr
新容器的。您可以通过使用back_inserter
和transform
来解决此问题,或者仅手动进行迭代以包装每个指针并一次插入一个指针。事实证明,您有充分的理由不希望此转换隐式进行。考虑一下:
如果这里允许隐式转换,那么对 DoSomething 的调用将是合法的。但是,这将导致新的
shared_ptr
开始引用ptr
所持有的资源。这是有问题的,因为当DoSomething
返回时此shared_ptr
超出范围时,它将发现它是资源的唯一shared_ptr
,并且将取消分配它。换句话说,使用原始指针调用 DoSomething 会隐式删除该指针!According to the documentation of Boost
shared_ptr
, theshared_ptr
constructor is markedexplicit
, meaning that there's no implicit conversion fromT*
s toshared_ptr<T>
. Consequently, when you're trying to insert the iterator range defining your old container into the new container, the compiler complains because there's no way of implicitly converting from the raw pointers of the old containers into theshared_ptr
s of the new container. You can fix this by either using aback_inserter
andtransform
, or by just doing the iteration by hand to wrap each pointer and insert it one at a time.It turns out that there's a good reason that you don't want this conversion to work implicitly. Consider:
If the implicit conversion were allowed here, then the call to
DoSomething
would be legal. However, this would cause a newshared_ptr
to start referencing the resource held byptr
. This is problematic, because when thisshared_ptr
goes out of scope whenDoSomething
returns, it will see that it's the onlyshared_ptr
to the resource and will deallocate it. In other words, callingDoSomething
with a raw pointer would implicitly delete the pointer!只是因为你说
例如,boost::shared_ptr
- 如果语义适合你,有boost::ptr_vector
它存储指针向量并负责释放它们当向量超出范围时。该容器有一个transfer
方法,您可以使用该方法来获取所获得的向量中所包含的指针的所有权。Just because you said
for instance, boost::shared_ptr
- if the semantics fit you, there isboost::ptr_vector
which stores a vector of pointers and is responsible for freeing them when the vector goes out of scope. This container has atransfer
method that you could use for taking ownership of the pointers cointained in the vector you get.只需像这样使用范围构造函数:
从概念上讲,它相当于:
现在使用范围构造函数,可以实现以下目的:
这使得处理多态类型的容器变得更加容易!
Just use the range constructor like so:
Conceptually it is equivalent to:
Now with the range constructor, the following is possible:
This makes dealing with containers of polymorphic types much easier!