传递派生共享指针的向量?

时间:2015-03-03 03:24:30

标签: c++ pointers c++11 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。

1 个答案:

答案 0 :(得分:2)

你可以试试这个。

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. 此功能模板使用名为&#34; SFINAE&#34;检查参数是否是派生类的智能指针的容器。


  3. 跟进

    从&#34;共享指针的容器转换为派生类&#34; to&#34;指向基类的共享指针的容器&#34;是可能的,而不是很困难。但是,我关心的是设计选择使用&#34;容器共享指针到基类&#34;会给你可接受的表现。


    让我们先讨论如何做到这一点。

    1. 我们可以使用std::shared_ptr<Base>从每个std::shared_ptr<Derived>对象创建一个std::static_pointer_cast对象。
    2. 要对列表中的所有条目应用std::static_pointer_cast,我们可以使用std::transform
    3. 如果您有许多派生类,则可以使用带有SFINAE检查的函数模板对每个派生类进行转换。
    4. 所以,代码如下:

      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);
          }
      };
      

      然而,这种方法有很多性能损失。

      • 必须为每个指向派生类的指针列表创建一个新的基类指针列表。它花费了大量的时间和精力来构建新的列表。
      • 通过指针访问对象。这种间接性使事情变得缓慢。
      • 由于对象未分配到紧凑数据结构中,因此缓存未命中将非常严重。

      我建议你评估性能,看看这种方法是否可以接受。否则,最好考虑其他一些设计选择。