Return 新实例或自身作为 std::shared_ptr 而不是原始指针

Return new instance or itself as std::shared_ptr rather than raw pointer

我实现了类似 CSS 的选择器系统,可以在某些对象树中使用。我的选择器在创建时并不是完美的。有时,可以用简单的选择器替换更复杂的选择器,这是一种不同的 class 类型。

我将此方法添加到我的选择器界面:

virtual std::shared_ptr<Selector> optimize(std::shared_ptr<Selector> target) const = 0;

但是有一个问题 - 如果选择器不能优化成更简单的 class,它应该 return 本身。例如,我有一个维护列表或项目的选择器。如果只有一项,这个选择器是多余的,应该 return 更简单的选择器,否则,它应该 return self.

std::shared_ptr<Selector> CSSChainedSelector::optimize() const
{
    if(sub_selectors.size()==1) {
        return sub_selectors[0]->optimize();
    }
    else if(sub_selectors.empty()) {
        return std::shared_ptr<Selector>(new InvalidSelector());
    }
    else {
        //THIS WILL CAUSE MEMORY ERROR IN THE FUTURE!!!
        return std::shared_ptr<Selector>(this);
    }
}

不过您不能从中创建 shared_ptr。如果这样做,则会导致对象被删除两次。共享指针只能从新实例创建。知道这一点,我不得不改变我的设计,现在有点疯狂:

std::shared_ptr<Selector> CSSChainedSelector::optimize(std::shared_ptr<Selector> target) const
{
    if(target.get() != this)
        return target;
    // this is probably redundant
    std::shared_ptr<CSSChainedSelector> self = std::dynamic_pointer_cast<CSSChainedSelector>(target);
    if(self) {
        if(chain_.length() == 1) {
            return chain_[0]->optimize(chain_[0]);
        }
    }
    else
        return target;
    return target;
}

这需要我这样调用方法:

std::shared_ptr<Selector> selector(new CSSChainedSelector);
// parsing happens
   ... some parsing ...
selector = selector->optimize(selector);

这是有道理的,因为只有从外部看到 class 时才能调用 optimize 方法(它不会改变 class)。更改 class 的优化可以在解析期间完成。

但是有没有办法在 class 自己的实例上安全地 return 共享指针?

注意:上面描述的优化看起来像微优化,因为我已经大大简化了问题。请关注"returning own instance as shared pointer".

的话题
#include <memory>

struct selector : std::enable_shared_from_this<selector>
{

  std::shared_ptr<selector> optimise()
  {

    // the case where we can't optimise, we return ourselves.
    return this->shared_from_this();
  }
};

更新:对不起,你的优化函数是常量。如果你 returning a shared_ptr to self 那么它必须是 shared_ptr to const:

#include <memory>

struct selector : std::enable_shared_from_this<selector>
{

  std::shared_ptr<const selector> optimise() const
  {

    // the case where we can't optimise, we return ourselves.
    return this->shared_from_this();
  }
};

除非你想return复制一份,但我认为这可能会打败练习的对象。