通过继承扩展shared_ptr

问题描述 投票:8回答:3

做这样的事情有什么不好?

class myclass : public std::shared_ptr<myotherclass> {
     // some code,  an allocation is never done
     std::string get_info () {
          if(*this != nullptr) return "<info>" + (this->info * 3) + "</info>";
          else return "";
     }
 };

[当类中没有完成分配时---只是为了提供如上的装饰?

c++ boost shared-ptr
3个回答
8
投票

原则上允许从STL类派生,请参阅herehere。但是,您必须注意,不应使用指向基类的指针-在这种情况下,即为std::shared_ptr<myotherclass>*

因此应禁止使用此方法及其变体:

std::shared_ptr<myotherclass>* ptr = new myclass(/* ... */);

...但是同意,这看起来有点综合。

为什么禁止?因为STL类没有虚拟析构函数。因此,当您想delete您分配的类时,派生的部分仍然保留。反过来,这会调用undefined behaviour并可能导致内存泄漏-即使您的派生类中没有一些分配。

为了这样做,一种可能性是从shared_ptr私下获得:

class myclass : private std::shared_ptr<myotherclass> {};
                ^^^^^^^

但是,这可能会带来二进制兼容性的问题,请参见this answer的注释。

一方面,即使允许使用前者,也可以减少出错的可能性,并且可以使用组合,将shared_ptr设为myclass的成员并公开所需的功能(缺点是有时不得不暴露很多)。或者,您可以设置一个独立的函数来执行您想要的操作...我知道您知道;-)


1
投票

因为您永远不会手动delete(并且永远不要手动delete任何东西,首先是shared_ptr的要点,所以虚拟析构函数并不是真正的问题。

但是可能会出现一些互操作性问题。

  1. 您只有在创建派生类的特定实例时才获得它。当您从shared_ptr之类的地方获得get_shared_from_this时,它将不包含您的info

  2. shared_ptr<T>上重载的功能模板将看不到继承。您的派生类将突然出现在std::static_pointer_cast之类的随机函数之外。

幸运的是,C ++标准库充满了整洁的可扩展性挂钩。您可以像这样安装自定义删除器:

template< typename t >
struct my_deleter
    : std::default_delete< t > {
    std::string info;

    my_deleter( std::string in_info )
        : info( std::move( in_info ) ) {}
};

std::shared_pointer< foo > myfoo( new foo, my_deleter{ "it's a foo" } );

并使用非成员函数检索信息:

template< typename t >
std::string get_my_info( std::shared_ptr< t > ptr ) {
    my_deleter< t > * dp = std::get_deleter< my_deleter< t > >( ptr );
    if ( ! dp ) return {};
    return dp->info;
}

这不是一个很好的程序体系结构,因为每个共享库只有一个自定义删除器插槽。不过,它可以在紧急情况下完成。


0
投票

我建议使用std :: enable_shared_from_this <>,然后使用this-> shared_from_this()。

© www.soinside.com 2019 - 2024. All rights reserved.