shared_ptr的容器,但使用原始指针进行迭代
Container of shared_ptr's but iterate with raw pointers
我有一个类,它包含一个列表,其中包含对另一个类对象的boost::shared_ptrs
。
提供对列表中元素的访问权限的类成员函数返回原始指针。为了保持一致性,我还希望能够使用原始指针而不是shared_ptrs进行迭代。因此,当我取消引用列表迭代器时,我想获取原始指针,而不是shared_ptr
。
我假设我需要为此编写一个自定义迭代器。这是对的吗?如果是这样,有人可以指出我正确的方向 - 我以前从未这样做过。
使用Boost transform_iterator的选项:
#include <list>
#include <boost/iterator/transform_iterator.hpp>
#include <tr1/memory>
#include <tr1/functional>
using std::list;
using std::tr1::shared_ptr;
using boost::transform_iterator;
using boost::make_transform_iterator;
using std::tr1::mem_fn;
using std::tr1::function;
struct Foo {};
struct Bar
{
typedef shared_ptr< Foo > Ptr;
typedef list< Ptr > List;
typedef function< Foo* (Ptr) > Functor;
typedef transform_iterator< Functor, List::iterator > Iterator;
Iterator begin()
{
return make_transform_iterator( fooptrs.begin(), mem_fn( &Ptr::get ) );
}
Iterator end()
{
return make_transform_iterator( fooptrs.end(), mem_fn( &Ptr::get ) );
}
List fooptrs;
};
C++11 可以轻松消除 function
包装器,但我没有方便的编译器来测试它。 如果您看到需要,您还可以使用类型擦除隐藏具体类型的Iterator
(我认为 Adobe 为此目的提供了一个免费的any_iterator
类模板。
我有时会看到人们使用boost::shared_ptr
的STL容器,而实际上不太明显且相对鲜为人知的boost::ptr_container
可能是更好的选择。
这可能是也可能不是其中一种情况,但考虑到 ptr_container
类的一个很好的属性是它们的迭代器具有"额外"间接寻址,这有助于保持事物的清洁和安全。
♀️ ...僵尸线...
如果你不能使用Boost(例如,它是你的公共接口的一部分,你不想把它作为用户的要求(,你可以相对容易地推出自己的。对于容器my_container
- 它可以是标准,boost,任何容器的幌子,但其实际实现隐藏在您的实现文件中并且不暴露给您的API - 持有任何指向类my_type
的智能指针,它将是这样的:
class iterator
{
public:
~iterator();
iterator( const iterator& other );
iterator& operator=( const iterator& other );
// The standard iterator traits (names must be lower-case)
typedef std::forward_iterator_tag iterator_category;
typedef my_type* value_type;
typedef std::ptrdiff_t difference_type;
typedef value_type* pointer;
typedef value_type reference;
iterator& operator++();
iterator& operator++( int );
reference operator*() const;
friend bool operator==( const iterator& it1, const iterator& it2 );
friend bool operator!=( const iterator& it1, const iterator& it2 );
private:
// Private, type-erased construction
friend class my_container;
explicit iterator( void* );
// Implementation hidden by pimpl
struct impl;
impl* _impl;
};
在 cpp 文件中,假设我们在引擎盖下使用shared_ptr
vector
:
// Define the Pimpl struct
struct iterator::impl
{
typedef std::vector< std::shared_ptr<my_type> >::iterator iterator;
iterator iter;
};
// Use void* as type erasure to hide the actual types from the user
iterator::iterator( void* wrappedIter )
: _impl( new impl( *reinterpret_cast<impl::iterator*>( wrappedIter ) ) )
{
}
// Copying
iterator::iterator( const iterator& other )
: _impl( new impl( *other._impl ) )
{}
iterator& iterator::operator=( const iterator& other )
{
_impl->iter = other._impl->iter;
return *this;
}
// ... could implement moving too ...
iterator::~iterator()
{
// Destroy the pimpl
delete _impl;
}
iterator& iterator::operator++()
{
++_impl->iter;
return *this;
}
iterator& iterator::operator++( int )
{
++_impl->iter;
return *this;
}
iterator::reference iterator::operator*() const
{
// This is where the magic happens: We convert the shared_ptr to a raw pointer.
return _impl->iter->second.get();
}
bool operator==( const iterator& it1, const iterator& it2 )
{
return *it1 == *it2;
}
bool operator!=( const iterator& it1, const iterator& it2 )
{
return !( it1 == it2 );
}
然后,您所需要的只是创建这些的方法。为此,my_container
的 begin()
/end()
函数如下所示:
my_container::iterator my_container::begin()
{
// The & allows our type erasure by invoking our void* constructor
auto iter = _data->vector.begin();
return iterator( &iter );
}
my_container::iterator my_container::end()
{
// The & allows our type erasure by invoking our void* constructor
auto iter = _data->vector.end();
return iterator( &iter );
}
这种类型擦除和获取成员变量的地址看起来有点冒险,但没关系,因为我们立即重新解释void*
并取消引用和复制它。
- 从堆栈分配的原始指针构造智能指针
- 将unique_ptr分配给原始指针
- 如何将唯一指针的 std::vector 转换为原始指针的 std::span?
- <Base> <Derived> 具有相同原始指针共享引用的 shared_ptr 和 shared_ptr 实例是否计数?
- C++原始指针和"delete"
- 为什么 C++ 地址中的矢量无法通过原始指针访问
- 如何正确实现具有原始指针的类的复制构造函数?
- 如何在将原始指针移动到基类构造函数之前从unique_ptr中提取原始指针
- 为包含原始指针的对象C++智能指针
- c++:复制、删除和运算符=在原始指针映射中
- C++模板,用于通过常量引用和原始指针传递向量
- C++为什么原始指针不会增加shared_ptr的引用计数?
- 从shared_ptr获取原始指针以将其传递给需要 raw 的函数
- 如何包装多级原始指针以赋予其容器语义
- 为什么我可以通过原始指针而不是shared_ptr来修改对象
- 将原始指针传递给接受unique_ptr作为参数的函数
- 为什么我们不允许将纯引用参数传递给 std::thread,但允许传递原始指针?
- 更改保留指向其字段的原始指针的对象地址
- 从原始指针(衰减的 C 样式数组)和大小生成范围::视图
- 如何在C++代码中灵活使用和替换标准::shared_ptr或标准::unique_ptr或原始指针?