我通常会发现需要创建多态对象的数组或向量。我通常更喜欢使用对基类的引用,而不是智能指针,因为它们更简单。
数组和向量被禁止包含原始引用,因此我倾向于使用指向基类的智能指针。但是,也可以选择使用std::reference_wrapper
:wrapper
从文档中可以看出,这就是它的预期用途之一,但是当出现包含多态对象的数组的主题时,常见的建议似乎是使用智能指针而不是std::reference_wrapper
。
我唯一的想法是,智能指针可以处理对象的生命周期稍微整洁一点吗?
TL:为什么在创建多态对象数组时,智能指针(如std::unique_ptr
)似乎比std::reference_wrapper
更可取?
发布于 2018-09-07 12:40:05
简单地说:
unique_ptr
是对象的所有者。它管理拥有对象的生存期。reference_wrapper
在内存中包装指向对象的指针。它执行而不是来管理包装对象的生存期。您应该创建一个unique_ptr
(或shared_ptr
)数组,以保证在不再需要对象时释放它。
发布于 2018-09-07 14:53:23
如果您有足够的主题性,可以编写一个poly_any<Base>
类型。
poly_any<Base>
是一个仅限于存储从Base
派生的对象的any
,它提供了一个向底层对象返回Base&
的.base()
方法。
一幅非常不完整的草图:
template<class Base>
struct poly_any:private std::any
{
using std::any::reset;
using std::any::has_value;
using std::any::type;
poly_any( poly_any const& ) = default;
poly_any& operator=( poly_any const& ) = default;
Base& base() { return get_base(*this); }
Base const& base() const { return const_cast<Base const&>(get_base(const_cast<poly_any&>(*this))); }
template< class ValueType,
std::enable_if_t< /* todo */, bool > =true
>
poly_any( ValueType&& value ); // todo
// TODO: sfinae on ValueType?
template< class ValueType, class... Args >
explicit poly_any( std::in_place_type_t<ValueType>, Args&&... args ); // todo
// TODO: sfinae on ValueType?
template< class ValueType, class U, class... Args >
explicit poly_any( std::in_place_type_t<ValueType>, std::initializer_list<U> il,
Args&&... args ); // todo
void swap( poly_any& other ) {
static_cast<std::any&>(*this).swap(other);
std::swap( get_base, other.get_base );
}
poly_any( poly_any&& o ); // todo
poly_any& operator=( poly_any&& o ); // todo
template<class ValueType, class...Ts>
std::decay_t<ValueType>& emplace( Ts&&... ); // todo
template<class ValueType, class U, class...Ts>
std::decay_t<ValueType>& emplace( std::initializer_list<U>, Ts&&... ); // todo
private:
using to_base = Base&(*)(std::any&);
to_base get_base = 0;
};
然后,您只需拦截将内容放入poly_any<Base>
的所有方法,并存储一个get_base
函数指针:
template<class Base, class Derived>
auto any_to_base = +[](std::any& in)->Base& {
return std::any_cast<Derived&>(in);
};
一旦您这样做了,您可以创建一个std::vector<poly_any<Base>>
,它是一个值类型的向量,这些值类型是从Base
派生而来的。
请注意,std::any
通常使用小缓冲区优化来在内部存储小对象,并在堆上存储较大的对象。但这是一个实现细节。
发布于 2018-09-07 12:51:33
基本上,reference_wrapper
是一个可变的引用:像引用一样,它不能是空的;但是就像指针一样,您可以在它的生命周期内为它指定指向另一个对象的引用。
但是,与指针和引用一样,reference_wrapper
不管理对象的生存期。这就是我们使用vector<uniq_ptr<>>
和vector<shared_ptr<>>
的目的:确保正确地释放引用的对象。
从性能的角度来看,vector<reference_wrapper<T>>
应该与vector<T*>
一样快速和高效的内存。但是,这两个指针/引用可能会变得悬空,因为它们并不是在管理对象生存期。
https://stackoverflow.com/questions/52222665
复制相似问题