我应该使用什么c ++ 11范例来最小化内存使用并最小化复制?

时间:2014-02-23 19:52:22

标签: c++ memory c++11 interface ownership

问题

我有一个抽象接口Series和一个具体的类Primary_Series,它通过存储大的std::vector<>值来满足接口。

我还有另一个具体的类Derived_Series,它本质上是Primary_Series的变换(例如一些大的Primary_Series乘以3),我想要节省空间,所以我不想将整个派生系列存储为成员。

template<typename T>
struct Series
{
  virtual std::vector<T> const& ref() const = 0;
};

template<typename T>
class Primary_Series : Series<T>
{
  std::vector<T>  m_data;
public:
  virtual std::vector<T> const& ref() const override { return m_data; }
}

template<typename T>
class Derived_Series : Series<T>
{
  // how to implement ref() ?
}

问题

我应该如何更改此接口/纯虚方法?

我不想按值返回该向量,因为它会为Primary_Series引入不必要的复制,但在Derived_Series的情况下,我肯定需要创建某种临时向量。但接下来我面临的问题是,一旦调用者完成了该向量,我该如何使该向量消失。

如果ref()返回对临时的引用,随着引用的消失,它会很好。

这是否意味着我应该使用某种std::weak_ptr<>?这符合Primary_Series的工作原理吗?

满足“最小化内存使用”和“最小化复制”要求的最佳方法是什么,包括在调用者完成后使Derived_Series临时消失?

3 个答案:

答案 0 :(得分:3)

接口设计很好,因为它带来了一些问题,因为C ++并不是真的很懒。

现在,由于Derived_Series应该是一个懒惰评估(因为你想节省空间)原始Primary_Series的变换,你不能返回一个完整的胖矢量的引用。 (因为这需要你先构建它。)

因此我们必须更改界面以及_Series共享数据的方式。使用std::shared_ptr<std::vector<>>Primary_SeriesDerived_Series之间共享数据,以便超出范围的Primary_Series无法使转换数据无效。

然后,您可以将界面更改为“类似矢量”。也就是说,实现一些(或所有)通常的数据访问函数(operator[]at() ...)和/或自定义迭代器,它们从原始系列返回转换后的值。这些将让你隐藏一些实现细节(变换的懒惰,数据的共享......),并且仍然能够以最大的效率返回变换的值,并让人们将你的类用作“矢量样”,所以你不必改变你的设计。 (〜任何使用过矢量的算法都可以在知道之后使用你的类。)

<强> I've also sketched out a very basic example of what I mean.

(注意:如果你有多线程设计和可变Primary_Series,你将不得不考虑一下你需要同步的地点和位置。)

--- ---编辑
在仔细考虑之后,我还要注意,Derived_Series的实现无论如何都会有点痛苦。它的方法必须按值返回,它的迭代器基本上是伪装成更高类迭代器的输入迭代器,因为对于延迟计算值的引用返回并不真正起作用,或者它必须填写它自己的数据结构,如评估原始系列的位置,这将带来完全不同的权衡集。

答案 1 :(得分:1)

一种解决方案是使用std::shared_ptr<vector<T> >将向量存储在基类中,并使用它来返回向量的值。基类只返回其成员值,派生类创建一个新的向量并通过shared_ptr返回。然后,当调用者不再需要为派生类返回的值时,它将被自动销毁。

或者,您可以将类设计为模仿std::vector<T>的接口,但设计基类以便返回转换后的值而不是常规值。这样,就不需要任何回报。如果你不想为std::vector<T>所有的函数编写方法,你可以做一些可以迭代并转换std::vector<T>的转换迭代器。那么你甚至不必拥有复杂的类层次结构。

答案 2 :(得分:1)

一种方法是定义自己的iterator并将vector<T>设为私有。基本上,您将拥有begin()end()的纯虚拟访问者。而Derived_Series将只包装Primary_Series的迭代器并动态转换值。