- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我有一个元素类型为 const std::shared_ptr<MyClass>
的 STL 容器.
我想为用户提供两种迭代器类型:
MyContainer::iterator
类型定义为 std::vector<const std::shared_ptr<MyClass>>::iterator
(应与 std::vector<const std::shared_ptr<const MyClass>>::const_iterator
类型相同
MyContainer::const_iterator
类型定义为 std::vector<const std::shared_ptr<const MyClass>>::iterator
(应与 std::vector<const std::shared_ptr<const MyClass>>::const_iterator
类型相同
换句话说,我希望“const
”指的是MyClass
常量,不是 shared_ptr
常数。我找到的获取第二个迭代器类型的解决方案是获取第一个,这很简单(例如使用 vector::begin
),然后使用 static_cast
将其转换为第二个类型(fixme:无需使用 const_cast
,因为我添加的是常量,而不是删除它)。
这是实现该目标的常见良好设计方法,还是有更好/更常见的方法?
最佳答案
typedefed as
std::vector<const std::shared_ptr<MyClass>>::iterator
(which should be the same type asstd::vector<std::shared_ptr<const MyClass>>::const_iterator
但它可能不是同一类型。迭代器不仅仅是指针。如果iterator
和 const_iterator
类型在 vector
中定义那么它们是完全不相关的类型:
template<typename T>
class vector
{
class iterator;
class const_iterator;
// ...
vector<const int>
是与 vector<int>
不同的类型因此它们的嵌套类型也不同。就编译器而言,它们是完全不相关的类型,即你不能只移动 const
。绕到此类型中的任何一点并获得兼容的类型:
vector<const shared_ptr<const T>>::iterator
您不能使用 const_cast
在不相关的类型之间进行转换。您可以使用 static_cast
转换 vector<T>::iterator
到 vector<T>::const_iterator
但这并不是真正的强制转换,您是从前者构造后者,这是允许的,因为标准要求进行这种转换。
您可以转换 shared_ptr<const T>
到 shared_ptr<T>
与 const_pointer_cast<T>
但同样只是因为它被定义为按标准工作,而不是因为类型本质上是兼容的,也不是因为它像普通的指针一样“正常工作”。
自 vector
的迭代器不提供您想要的深度常量,您需要自己编写,但这并不难:
class MyClass { };
class MyContainer
{
typedef std::vector<std::shared_ptr<MyClass>> container_type;
container_type m_cont;
public:
typedef container_type::iterator iterator;
class const_iterator
{
typedef container_type::const_iterator internal_iterator;
typedef std::iterator_traits<internal_iterator> internal_traits;
const_iterator(internal_iterator i) : m_internal(i) { }
friend class MyContainer;
public:
const_iterator() { }
const_iterator(iterator i) : m_internal(i) { }
typedef std::shared_ptr<const MyClass> value_type;
typedef const value_type& reference;
typedef const value_type* pointer;
typedef internal_traits::difference_type difference_type;
typedef internal_traits::iterator_category iterator_category;
const_iterator& operator++() { ++m_internal; return *this; }
const_iterator operator++(int) { const_iterator tmp = *this; ++m_internal; return tmp; }
reference operator*() const { m_value = *m_internal; return m_value; }
pointer operator->() const { m_value = *m_internal; return &m_value; }
// ...
private:
internal_iterator m_internal;
mutable value_type m_value;
};
iterator begin() { return m_cont.begin(); }
const_iterator begin() const { return const_iterator(m_cont.begin()); }
// ...
};
该迭代器类型缺少一些东西(operator--
、operator+
),但它们很容易添加,遵循与已经展示的相同的想法。
要注意的关键点是为了 const_iterator::operator*
要返回引用,需要有一个 shared_ptr<const MyClass>
作为迭代器成员存储的对象。该成员充当 shared_ptr<const MyClass>
的“缓存”值,因为底层容器的实际元素是不同的类型,shared_ptr<MyClass>
,因此您需要在某处缓存转换后的值,以便可以返回对它的引用。注意这样做稍微违反了迭代器要求,因为以下内容没有按预期工作:
MyContainer::const_iterator ci = c.begin();
const shared_ptr<const MyClass>& ref = *ci;
const MyClass* ptr = ref.get();
++ci;
(void) *ci;
assert( ptr == ref.get() ); // FAIL!
断言失败的原因是 *ci
不返回对容器底层元素的引用,而是返回迭代器的一个成员,该成员通过以下增量和取消引用进行修改。如果此行为 Not Acceptable ,则需要从迭代器返回一个代理而不是缓存一个值。或者返回 shared_ptr<const MyClass>
当const_iterator
被取消引用。 (很难做到 100% 正确是 STL 容器不尝试对深度常量建模的原因之一!)
boost::iterator_adaptor
为您完成了很多定义您自己的迭代器类型的工作。实用程序,所以上面的例子只对说明有用。使用该适配器,您只需执行此操作即可获得具有所需行为的自定义迭代器类型:
struct iterator
: boost::iterator_adaptor<iterator, container_type::iterator>
{
iterator() { }
iterator(container_type::iterator i) : iterator_adaptor(i) { }
};
struct const_iterator
: boost::iterator_adaptor<const_iterator, container_type::const_iterator, std::shared_ptr<const MyClass>, boost::use_default, std::shared_ptr<const MyClass>>
{
const_iterator() { }
const_iterator(iterator i) : iterator_adaptor(i.base()) { }
const_iterator(container_type::const_iterator i) : iterator_adaptor(i) { }
};
关于C++11 强制转换指向 shared_ptr 对象容器的常量迭代器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15164330/
使用 shared_ptr 时,我应该只使用 shared_ptr 吗?申报一次或申报shared_ptr无论我经过哪里? 所以在我新建实例的函数中,我将它包装在 shared_ptr 中但是当我从函
#include #include #include using namespace std; struct Node { Node(int data, boost::shared_pt
对于我目前正在处理的代码,我们有时需要使用较旧的编译器在一些较旧的系统上进行编译(例如,我们在较旧的 IBM BlueGene/L 上运行 sims,其支持契约(Contract)规定了一些非常旧的
我正在阅读 this answer作者指的是boost best practices其中说: Avoid using unnamed shared_ptr temporaries to save ty
我正在处理几个类,我想知道如何在我的应用程序类中使用普通成员,而该成员需要使用 shared_from_this()? 这里有一些代码来阐明我的意思(见评论) class Observable { p
我有一个 Foo 类,其中包含一个 Hotel 类 的 shared_ptr,以及一个 Rules 类(位于 namespace Rules 内): class Foo { public: //
我想不通。看起来我遗漏了一些简单的东西?我要在 MakePointToSameValue 中输入什么,以便在点 (1) b.ptr 和c.ptr 与a.ptr 指向同一个 换句话说,a.ptr.get
我已尽我所能制作了 SSCE。我怀疑共享指针在我在 main 中请求它们之前解构(释放)了我的对象。如何在不完全绕过共享指针的情况下防止这种情况发生?这是一个程序中的孤立问题,否则可以通过使用 sha
这个问题在这里已经有了答案: Set shared_ptr with new_pointer that is old_pointer + offset (1 个回答) 关闭 4 年前。 我目前正在学
假设我们有一个类,成员如下 std::map> member_我们无法替换 member通过具有 std::shared_ptr 的 map ,因为该类必须对 ObscureType 的非常量函数进行
我正在用 C++ 做学校作业(我还在学习)。我正在尝试实现随机生成的二叉树结构,使用 shared_ptr 在多个地方存储节点的信息(我需要它作为作业)。考虑以下示例代码(这是我的小测试程序): #i
我有以下类(class) struct Images { std::vector > ptr_vector; } 将 ptr_vector 放入 std::shared_ptr 中不会在复制
我刚刚对一个项目进行了大规模重构,添加了一个基类来代替现在所说基类的派生类(因为我想要这个类的更多“类型”)。 我的问题是,一些实用函数将原始类 A 的引用作为 shared_ptr,因此函数声明如下
我记得 Scott Meyers 教我的 func(shared_ptr(new P), shared_ptr(new Q)); 是危险的,因为(如果我没记错的话)内存分配、引用计数(构造)和分配给
给定 struct X { void f(std::shared_ptr); }; auto x(std::make_shared()); 我大概可以安全地做 x->f(std::move(x
我试着介绍了一些const一些新代码的正确性(实际上是功能范例),发现我无法传递 std::shared_ptr到一个需要 std::shared_ptr 的函数.请注意,我不想放弃 constnes
我需要将原始指针包装到 shared_ptr 中,以便将其传递给函数。该函数在返回后不保留对输入对象的任何引用。 { MyClass i; shared_ptr p(&i); f(p);
我在继承链中有4个类:A-> B-> C,A-> B-> D,其中B是唯一的类模板。 我想拥有一个在id和对象指针(C或D)之间映射的std::map,但是我在将make_shared输出分配给std
boost::shared_ptr 是否解决原始指针问题? Base* p = new Base(); shared_ptr sp(p); shared_ptr sq(p); 两个 shared_
How can shared_ptr be a subclass of shared_ptr? 我想知道如何实现模板类 C这样 C是 C 的子类? 我已经观察到上述情况,例如 shared_ptr和
我是一名优秀的程序员,十分优秀!