vector <shared_ptr <t>&gt;之间的有效转换和vector <shared_ptr <const t =“”>&gt; </shared_ptr <const> </shared_ptr <t>

时间:2012-10-15 21:27:57

标签: c++ c++11

我有一个班级:

class X {
  vector<shared_ptr<T>> v_;

 public:
  vector<shared_ptr<const T>> getTs() { return v_; }
};

vector shared_ptr类型为T。出于某种原因,它需要公开一个方法来返回这个向量。但是,我不希望修改向量的内容,也不希望对象被指向。所以我需要返回vector shared_ptr<const T>

我的问题是,有没有有效的方法来实现这一目标?如果我只是返回它,它可以工作,但它需要重建一个矢量,这是一种昂贵的。

感谢。

4 个答案:

答案 0 :(得分:4)

你不能直接这样做 - 但你可以在容器上定义“views”,让你做一些非常相似的事情,如果你想确保你的pointees是const:

boost::any_range<
  std::shared_ptr<const int>,
  boost::random_access_traversal_tag,
  std::shared_ptr<const int>,
  std::ptrdiff_t
> foo(std::vector<std::shared_ptr<int>>& v)
{
  return v;
}

一个简单的变换迭代器适配器/转换范围也可以做到这一点,我只是用它来说明这一点。

答案 1 :(得分:2)

为什么不将它作为一组iterator s?

返回
class X {
  vector<shared_ptr<T>> v_;
  class const_iterator : std::iterator< std::bidirectional_iterator_tag, T >
  {
    vector<shared_ptr<T>>::iterator it;
    const_iterator( vector<shared_ptr<T>>::iterator& v ) :it (v) { }
    const T& operator*() { return const_cast<const T>( **it ); }
    //forward all methods
  }

   public:
  const_iterator ts_begin() { return const_iterator(v_.begin()); }
  const_iterator ts_end() { return const_iterator(v_.end()); }
};

或类似的东西?这使您可以完全控制类型及其访问方式。此外,您可以稍后更改类型,而无需更改API。

答案 2 :(得分:1)

您将按值返回,因此无论您返回原始数据的副本,向量还是shared_ptr<T const>向量的副本,成本都是相同的:一个内存分配和N个原子增量(大约)。

如果要避免的是创建返回的向量(即按值返回),则不可能因为不同的模板实例化是不相关的类型,无论模板的参数有多相关。

答案 3 :(得分:0)

典型的解决方案是通过const引用返回:

class X {
  vector<shared_ptr<T>> v_;

 public:
  const vector<shared_ptr<T>>& getTs() const { return v_; }
};

使用此返回类型vector<shared_ptr<T>>&,其他对象无法修改内部向量。

但是然而这打破了封装。你的v_不再是X的私密部分 - 它只是私有的写作方面。

真正的封装是:

class X {
  vector<shared_ptr<T>> v_;

 public:
  class const_ts_iterator  {
  public: 
   //define all necessary stuff
  private:
     vector<shared_ptr<T>>::const_iterator it;
  };
  size_t getTsSize() const { return v_.size; }
  const T* getTsAt(size_t i) const { return v_.at(i).get(); }
  const_ts_iterator beginTs() const { return v_.cbegin(); } 
  const_ts_iterator endTs() const { return v_.cend(); } 
};