c++ - 传递派生共享指针的 vector ?

标签 c++ pointers c++11 vector

允许将指向派生类的共享指针 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; }

主要思想是:

  1. 我们可以通过编译器已知的具体类型信息访问元素,而不是通过基类指针访问元素。
  2. 这个函数模板使用了一个叫做“SFINAE”的技巧来检查参数是否是派生类的智能指针的容器。


跟进:

从“指向派生类的共享指针的容器”到“指向基类的共享指针的容器”的转换是可能的,而且不是很困难。但是,我担心使用“指向基类的共享指针容器”的设计选择是否会给您带来可接受的性能。


让我们先讨论一下如何去做。

  1. 我们可以创建一个 std::shared_ptr<Base>来自每个 std::shared_ptr<Derived> 的对象使用 std::static_pointer_cast 对象.
  2. 申请std::static_pointer_cast在列表的所有条目上,我们可以使用 std::transform .
  3. 如果您有许多派生类,则可以使用带有 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/

相关文章:

C++/Visual Studio - 如何输出到测试输出窗口?

c++ - 四元数到方向 vector

c - 结构数组和 sizeof

c++ - 在 CMake 项目中链接静态库 - 未定义的引用

c++ - sort() 是否自动使用 move 语义?

c++ - 在 CMake Env 中包含 libcurl

c++ - 正则表达式比 if else 快吗?

c++ - 将指向未知实例(但已知类)的已知成员的指针转换为拥有实例

c++ - 如何从 vector 指针中删除指针

c++ - 空终止字符数组与字符串对象