【问题标题】:shared_from_this() returns std::shared_ptr<const X>, not std::shared_ptr<X>shared_from_this() 返回 std::shared_ptr<const X>,而不是 std::shared_ptr<X>
【发布时间】:2017-11-18 01:25:43
【问题描述】:

好的,这个让我难住了。显然我错过了一些东西,所以我希望有人能告诉我它是什么。

我正在开发一个 C++17 库。我编写了一个由Node 对象和一个自定义迭代器Node::iterator 组成的自定义树数据结构,用于遍历树。迭代器如下所示:

template <typename T>
class NodeIterator {
public:
    using value_type = T;
    using difference_type = std::ptrdiff_t;
    using pointer = std::shared_ptr<T>;
    using reference = T&;
    using iterator_category = std::forward_iterator_tag;

    NodeIterator() = default;
    NodeIterator(pointer n);

    // Etc.
}

后来……

template class NodeIterator<Node>;
template class NodeIterator<const Node>;

当我将标准迭代器方法(begin()end() 和 const 等效项)添加到父类 Tree 时,我可以控制迭代器的初始值。所以我可以说

Node::iterator Tree::begin() const {
    return Node::iterator(_root);
}

其中_rootstd::shared_ptr&lt;Node&gt;。这很好用。

但是,我不满足于单独离开,我希望节点本身上有这些迭代器方法。这样我就可以从任何节点遍历子树,完全消除 Tree 类,然后只传递 Node 对象。

我声明Node

class Node : public std::enable_shared_from_this<Node> {
public:
    using iterator = NodeIterator<Node>;
    using const_iterator = NodeIterator<const Node>;

    iterator begin() const;
    iterator end() const;
    const_iterator cbegin() const;
    const_iterator cend() const;

    // Etc.
}

并将迭代器方法定义为

Node::iterator Node::begin() const {
    return Node::iterator(this->shared_from_this());
}

Node::iterator Node::end() const {
    return Node::iterator(nullptr);
}

Node::const_iterator Node::cbegin() const {
    return Node::const_iterator(this->shared_from_this());
}

Node::const_iterator Node::cend() const {
    return Node::const_iterator(nullptr);
}

然后编译器大声抱怨return 语句:

src/node.cc:79:9: error: no matching conversion for functional-style cast from
      'shared_ptr<const Node>' to 'Node::iterator' (aka 'NodeIterator<Node>')
        return Node::iterator(this->shared_from_this());
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

以后……

include/example.h:344:2: note: candidate constructor not viable: no known
      conversion from 'shared_ptr<const Node>' to 'shared_ptr<Node>' for
      1st argument
        NodeIterator(pointer n);
        ^

在另一种方法Node::appendChild()中,我自动将父节点(std::shared_ptr&lt;Node&gt;)设置为this-&gt;shared_from_this(),效果很好。

如果我注释掉 Node::begin()Node::end() 并且只在我的循环中使用 cbegin()cend(),它也可以正常工作。

什么给了?

【问题讨论】:

  • 大概你的一个成员函数是const 而另一个不是?

标签: c++ c++11 iterator shared-ptr


【解决方案1】:

shared_from_this 具有 const 和非常量重载。见cppreference。在您的 const begin 中,this 是指向 const 的指针,并调用将 shared_ptr 返回给 const 的 const 重载。

【讨论】:

  • 我更新了我的问题以添加更多关于我如何声明和定义迭代器方法的细节。您能否详细介绍一下您建议的解决方案是什么?
  • @MatthewRatzloff 让begin() const 返回一个const_iteratorbegin()(非常量)返回一个iterator,就像他们应该的那样。能够通过迭代来修改 const 对象会很糟糕。
  • @ChrisDodd 谢谢!我错误地认为cbegin()cend() 常量等价物(向量、列表、地图...)。没有意识到你应该只是超载begin()end()。我的大脑显然在这两个结束时都被 const 扭曲了......
  • cbegin/cend 存在,因此您可以轻松地从非常量对象获取 const 迭代器,而无需执行显式 const_cast。大多数情况下,您只需使用重载的 begin/end 即可处理 const 或非 const。
猜你喜欢
  • 2019-10-20
  • 2017-08-06
  • 1970-01-01
  • 1970-01-01
  • 2015-07-23
  • 2015-04-04
  • 1970-01-01
  • 2019-06-13
  • 2020-09-01
相关资源
最近更新 更多