我实现了类似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;。
答案 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();
}
};
除非您想要返回副本,但我认为这可能会破坏练习的目的。