谁应该清除通过引用检索的向量?

时间:2015-06-15 09:29:57

标签: c++ vector pass-by-reference

我们说我有这个非常简单的代码:

  std::vector<int> getVector( int size )
  {
      std::vector<int> res;
      for ( size_t i = 0; i != size; ++i )
          res.push_back( i* 23 );
      return res;
  }

  int main ()
  {
      std::vector<int> v;
      v = getVector(10);
      std::cout << "Size1 is " << v.size() << std::endl;
      v = getVector(15);
      std::cout << "Size2 is " << v.size() << std::endl;
  }

输出:

  

Size1是10

     

Size2是15

现在,让我们说我想要更改getVector以避免无用的对象副本并优化速度和内存使用。因此,getVector现在将获得对要填充的向量的引用。

  void getVector( int size, std::vector<int>& res )
  {
      for ( size_t i = 0; i != size; ++i )
          res.push_back( i* 23 );
  }

现在,如果我改变主要功能,而不注意:

  int main ()
  {
      std::vector<int> v;
      getVector(10,v);
      std::cout << "Size1 is " << v.size() << std::endl;
      getVector(15,v);
      std::cout << "Size2 is " << v.size() << std::endl;
  }

输出:

  

Size1是10

     

Size2是25

这不是我原来的。

我已经完成了这种改变(用参考传递的对象取代了返回值)的时间音调,而且我一直在问自己同样的问题:谁应该清除向量?

是否有任何&#34; guidline&#34;或者&#34;一般规则&#34;在这种情况下说谁应该清除矢量?

该功能本身应该这样做吗?

  void getVector( int size, std::vector<int>& res )
  {
      res.clear();
      for ( size_t i = 0; i != size; ++i )
          res.push_back( i* 23 );
  }

或者来电者应该这样做吗?

  int main ()
  {
      std::vector<int> v;
      getVector(10,v);
      std::cout << "Size1 is " << v.size() << std::endl;
      v.clear();
      getVector(15,v);
      std::cout << "Size2 is " << v.size() << std::endl;
  }

修改

如许多人所报告的那样,例子可能是错误选择,因为它是一个错误的优化&#34;但是可能存在这样的情况:通过引用检索向量并且问题仍然存在。例如:

bool hasData( std::vector<int>& retrievedData );

void splitVector( const std::vector<int>& originalVector,
                  std::vector<int>& part1,
                  std::vector<int>& part2 );

...

4 个答案:

答案 0 :(得分:4)

  

现在,让我们说我想改变getVector以避免无用的对象   复制并优化速度和内存使用。所以getVector现在会得到   对要填充的向量的引用。

你应该考虑一些事情:

  • 在您的第一个示例中,没有副本,因为RVO / NRVO编译器优化。
  • 如果使用C ++ 11,则所有STL容器都有移动构造函数。因此,在这样的情况下永远不会被复制。
  • 如果您希望收到参考资料,除了来电者方面没有其他(正确)方式。
  • 您可以在vector::reserve函数的开头使用getVector优化此代码段。

答案 1 :(得分:2)

在第一个例子中,该函数被称为&#34; getVector&#34;这适合描述函数的作用。它返回一个具有一定数量元素的向量,如预期的那样。

在第二个例子中,同样不适用。该函数仍被称为&#34; getVector&#34;但现在你要清除矢量。它不再描述函数,因为您将向量传递给它并使用它做事。它更像是&#34; takeAVectorClearItAndInitializeIt&#34;。而且您可能不想命名这样的函数或在代码中使用它。 (当然,我夸大了一点,但你明白了)

为了使函数易于理解,它应该有一个清晰的函数,而不是在后台做隐藏的事情(比如清除客户端的向量)。如果我要使用你的功能,我可能会对为什么我的矢量被清除感到困惑。

通常它是负责管理自己的变量的客户端代码。即使客户端代码调用一个函数来清除向量,责任仍然在客户端代码中,以清除其向量。在您的情况下,您从客户端代码知道&#34; getVector&#34;函数是因为你把它们都放在一起所以它不会让你感到困惑,但是当你编写的代码只需要两个函数中的一个时(清除OR初始化),你可能会做一些影响所有使用这个函数的代码并创建更多的代码。问题。

更具体地回答您的问题。

如果你不想复制通过引用的向量,可以将函数命名为更具描述性的函数,例如&#34; initializeVector&#34;这样你就可以更清楚自己在做什么了。

你通常应该打电话给&#39;清除&#39;从客户端代码来看,所以你的第一个例子会更好,直到遇到性能问题。 (当你获得不同的向量时,明确是隐含的)

答案 2 :(得分:1)

没有单身权利。但是想一下stringstream类对象以供参考。打算重用此类对象的人需要在重用对象之前进行清理。创建对象的人通常负责删除对象。

答案 3 :(得分:0)

两者都没有。相反,您应该重新考虑您的设计决策。您为消除(可能是理论上的)性能问题而执行的操作 - 我从您的措辞中读到了这个

  

避免无用的对象副本并优化速度和内存使用

取代了两个具体问题:

  1. 此功能的性能瓶颈是什么?
  2. 出于性能原因,我应该避免std::vector吗?
  3. 相对容易回答,是一个抽象而又难以回答的问题,但它会给你(和我们)带来严重的麻烦:你的“优化”实际上会导致性能下降