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

发布于 2024-10-14 05:23:49 字数 5073 浏览 6 评论 0原文

是否有一种简洁、通用的方法来将常规/哑指针的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

∞琼窗梦回ˉ 2024-10-21 05:23:49

您可以使用 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() 来强调这一点 - 但这远非保证。

You could use 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);

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.

一杆小烟枪 2024-10-21 05:23:49

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

Combine ::std::back_inserter with ::std::transform and a little function that will perform the conversion. If you also use reserve, this should be reasonably efficient. Once all the templates are expanded you will essentially get this code:

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();
}
ぽ尐不点ル 2024-10-21 05:23:49

根据 Boost shared_ptr 的文档< /a>,shared_ptr 构造函数被标记为显式,这意味着没有从 T*shared_ptr的隐式转换。。因此,当您尝试将定义旧容器的迭代器范围插入新容器时,编译器会发出警告,因为无法从旧容器的原始指针隐式转换为 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 会隐式删除该指针!

According to the documentation of Boost shared_ptr, the shared_ptr constructor is marked explicit, meaning that there's no implicit conversion from T*s to shared_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 the shared_ptrs of the new container. You can fix this by either using a back_inserter and transform, 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:

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

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

If the implicit conversion were allowed here, then the call to DoSomething would be legal. However, this would cause a new shared_ptr to start referencing the resource held by ptr. This is problematic, because when this shared_ptr goes out of scope when DoSomething returns, it will see that it's the only shared_ptr to the resource and will deallocate it. In other words, calling DoSomething with a raw pointer would implicitly delete the pointer!

み格子的夏天 2024-10-21 05:23:49

只是因为你说例如,boost::shared_ptr - 如果语义适合你,有 boost::ptr_vector 它存储指针向量并负责释放它们当向量超出范围时。该容器有一个 transfer 方法,您可以使用该方法来获取所获得的向量中所包含的指针的所有权。

Just because you said for instance, boost::shared_ptr - if the semantics fit you, there is boost::ptr_vector which stores a vector of pointers and is responsible for freeing them when the vector goes out of scope. This container has a transfer method that you could use for taking ownership of the pointers cointained in the vector you get.

拒绝两难 2024-10-21 05:23:49

只需像这样使用范围构造函数:

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

这使得处理多态类型的容器变得更加容易!

Just use the range constructor like so:

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

Conceptually it is equivalent to:

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

Now with the range constructor, the following is possible:

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

This makes dealing with containers of polymorphic types much easier!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文