【问题标题】:Avoid making copies with vectors of vectors避免使用向量的向量进行复制
【发布时间】:2009-12-11 18:37:40
【问题描述】:

我希望能够拥有某种类型的向量,例如:

vector<vector<MyStruct> > vecOfVec;

然后我创建一个 MyStruct 的向量并填充它。

vector<MyStruct> someStructs;
// Populate it with data

然后最后将 someStructs 添加到 vecOfVec;

vecOfVec.push_back(someStructs);

我想要做的是避免在推送向量时调用复制构造函数。我知道这可以通过使用指针向量来完成,但如果可能的话,我想避免这种情况。

我想到的一个策略似乎可行,但我不知道我是否过度设计了这个问题。

// Push back an empty vector
vecOfVec.push_back(vector<MyStruct>());

// Swap the empty with the filled vector (constant time)
vecOfVec.back().swap(someStructs);

这似乎可以添加我的向量而无需进行任何复制,但这似乎是编译器在优化期间已经在做的事情。

你认为这是一个好策略吗?

编辑:根据一些建议简化了我的交换语句。

【问题讨论】:

  • 为什么不想只存储指针?
  • 小问题:你可以调用 vecOfVec.back().swap(someStructs)。
  • 将你的代码移动到一个move函数中,我认为它很好,它看起来有点像C++0x:template &lt;typename Cont&gt; void move(Cont&amp; pContainer, typename Cont::value_type&amp; pValue){ pContainer.push_back(typename Cont::value_type()); pContainer.back().swap(pValue);}这个函数将数据移动到一个容器的后面通过交换。未经测试:P

标签: c++ optimization memory-management stl vector


【解决方案1】:

交换技巧和 C++03 一样好。在 C++0x 中,您将能够通过 std::move 使用向量的移动构造函数以更明显的方式实现相同的目的。

另一种选择是不创建单独的vector&lt;MyStruct&gt;,而是让创建它的代码接受vector&lt;MyStruct&gt;&amp; 参数并对其进行操作。然后,向外部 vector&lt;vector&lt;MyStruct&gt;&gt; 添加一个新的空元素,并传递对填充它的代码的引用。

【讨论】:

  • Pavel,这可能被视为一个问题,因为为了节省性能(复制),您更改了算法的语义。突然间,仅仅因为它是一个大型数据集,您将避免返回值语义。恕我直言,这违反了面向对象的编程原则。
  • C++ 不是纯粹的 OO 语言是有原因的,实用主义是其中很大一部分。此外,在返回值上使用 byref 是一项长期存在的性能改进技术,对于那些产生明显改进的情况,它没有任何问题。我同意 return 风格更自然,但 swap 技巧不是(你必须使用一个或另一个来获得不错的性能)。
【解决方案2】:

我知道这可以通过 使用指针向量,但我会 如果可能的话,希望避免这种情况。

为什么?

这将是最直观/可读/可维护的解决方案,并且比任何人想出的任何奇怪的黑客(例如您展示的交换)都要好得多。

【讨论】:

  • 在很多情况下,我确实使用了指针向量。但由于我目前正在处理的部分问题,我想避免它。我宁愿举一个简单的例子,而不是给出我怀疑你是否有兴趣阅读的解释段落。另一方面,我所做的远非某种黑客行为。
  • 这些对我来说看起来不像是“奇怪的黑客”。
  • 我认为它们是 hack,因为向量不应该以这种方式使用,而且这样的代码不直观。 “奇怪”可能是一个很强的形容词。
【解决方案3】:

蒂姆,

有一个常见的模式可以解决这个问题。这称为智能指针,最好使用的是 boost::shared_ptr。

然后,永远不要按值传递向量或存储它。相反,存储 boost::shared_ptr >。您不需要关心分配/解除分配(当包含向量被销毁时,其他向量也会被销毁,就像在您的代码中一样),您可以以几乎相同的方式访问内部成员。然而,通过智能指针对象的引用计数机制可以避免复制。

让我告诉你怎么做。

using boost::shared_ptr;
vector<shared_ptr<vector<MyStruct> > vecOfVecs;
shared_ptr<vector<MyStruct> > someStructs(new vector<MyStruct>);
// fill in the vector MyStructs
MyStructs->push_back(some struct.... as you usually do).  
//...
vecOfVecs.push_back(someStructs); // Look! No copy!

如果您还没有使用 boost::shared_ptr,我建议您从 boost.org 下载它,而不是自己实现。真的是不可替代的工具,很快就会进入C++标准库。

【讨论】:

  • P.S.这也是从函数中返回向量的正确方法,以避免引用参数上传语义。
【解决方案4】:

您可以执行类似 vect.push_back(vector()); 之类的操作并做 vect.back().push_back(MyStruct());或使用智能指针并拥有一个指向vector

的智能指针向量

【讨论】:

    【解决方案5】:

    我认为交换的想法已经很好,但可以写得更容易:

    vecOfVec.push_back(vector<MyStruct>());
    vecOfVec.back().swap(someStructs);
    

    【讨论】:

      猜你喜欢
      • 2016-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-06
      • 2015-01-31
      • 1970-01-01
      • 1970-01-01
      • 2017-09-26
      相关资源
      最近更新 更多