允许将指向派生类的共享指针 vector 传递给一个函数的正确方法是什么,该函数需要指向基类的共享指针 vector 而不执行复制?
代码如下:
#include <string>
#include <vector>
#include <memory>
class Base {
public:
std::string Name;
};
using BaseList = std::vector<std::shared_ptr<Base>>;
class Derived : Base {
};
using DerivedList = std::vector<std::shared_ptr<Derived>>;
class BaseHandler {
public:
void process( BaseList list ) {
}
};
int main() {
DerivedList list;
BaseHandler bh;
bh.process( list );
}
代码链接:http://coliru.stacked-crooked.com/a/5a5b18ba3b2a4f08
编辑:DOH!!!我发错了。抱歉...这是 shared_ptr 一个。
最佳答案
你可以试试这个。
template <class T,
class SharedPtr = typename T::value_type,
class Element = typename SharedPtr::element_type,
class IsDerived = typename std::enable_if<std::is_base_of<Base, Element>::value, void*>::type
>
void process(const T& t) { std::cout << "process" << std::endl; }
主要思想是:
- 我们可以通过编译器已知的具体类型信息访问元素,而不是通过基类指针访问元素。
- 这个函数模板使用了一个叫做“SFINAE”的技巧来检查参数是否是派生类的智能指针的容器。
跟进:
从“指向派生类的共享指针的容器”到“指向基类的共享指针的容器”的转换是可能的,而且不是很困难。但是,我担心使用“指向基类的共享指针容器”的设计选择是否会给您带来可接受的性能。
让我们先讨论一下如何去做。
- 我们可以创建一个
std::shared_ptr<Base>
来自每个std::shared_ptr<Derived>
的对象使用std::static_pointer_cast
对象. - 申请
std::static_pointer_cast
在列表的所有条目上,我们可以使用std::transform
. - 如果您有许多派生类,则可以使用带有 SFINAE 检查的函数模板(如前所述)使每个派生类都可以进行转换。
因此,代码如下所示:
DerivedList derivedList;
// Put items into derivedList
BaseList baseList;
baseList.reserve(derivedList.size());
std::transform(std::begin(derivedList), std::end(derivedList), std::back_inserter(baseList),
[](const std::shared_ptr<Derived>& shptr)
{
return std::static_pointer_cast<Base>(shptr);
});
BaseHandler bh;
bh.process(baseList);
或者:
class BaseForwarder
{
public:
template <class T,
class SharedPtr = typename T::value_type,
class Element = typename SharedPtr::element_type,
class IsDerived = typename std::enable_if<std::is_base_of<Base, Element>::value, void*>::type
>
void process(const T& derivedList)
{
BaseList baseList;
baseList.reserve(derivedList.size());
std::transform(std::begin(derivedList), std::end(derivedList), std::back_inserter(baseList),
[](const SharedPtr& shptr)
{
return std::static_pointer_cast<Base>(shptr);
});
BaseHandler bh;
bh.process(baseList);
}
};
但是,这种方法有相当多的性能损失。
- 必须为每个派生类指针列表创建一个新的基类指针列表。构建新列表会花费大量时间和内存。
- 对象是通过指针访问的。这种间接减慢了速度。
- 由于对象没有分配到紧凑的数据结构中,缓存未命中会很严重。
我建议您评估性能,看看这种方法是否可以接受。否则,最好考虑一些其他的设计选择。
关于c++ - 传递派生共享指针的 vector ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28823540/