将新实例或其自身返回为std :: shared_ptr而不是原始指针

时间:2016-09-05 16:22:38

标签: c++ pointers shared-ptr

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

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

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

但是有一个问题 - 如果选择器无法优化到某个更简单的类中,它应该返回自己。例如,我有一个维护列表或项目的选择器。如果只有一个项目,则此选择器是多余的,应该返回更简单的选择器,否则,它应该返回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);

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

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

注意:上述优化看起来像微优化,因为我已经大大简化了问题。请关注&#34;将自己的实例作为共享指针返回&#34;。

1 个答案:

答案 0 :(得分:4)

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

更新:原谅我,你的优化功能是const。如果您将shared_ptr返回给self,则它必须是const的shared_ptr:

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

除非您想要返回副本,但我认为这可能会破坏练习的目的。