像这样的for循环被认为是不好的做法吗?

时间:2017-03-19 03:11:04

标签: c++ for-loop

所以对于这个例子,假设我有一个名为original的std :: vector,我想把它分成两半,分成两个不同的向量。假设原件具有均匀的元素。

std::vector<int> firstHalf;
std::vector<int> secondHalf;

for (int i = 0, j = original.size()/2; i < original.size() / 2; i++, j++)
{
    firstHalf.push_back(original[i]);
    secondHalf.push_back(original[j]);
}

更明显的方法是使用两个单独的for循环,一个用于填充firstHalf,另一个用于填充secondHalf。

正在编写for循环,就像我认为不好的做法一样吗?从我的测试来看,这个解决方案比两个单独的for循环更有效。

5 个答案:

答案 0 :(得分:11)

实际上,您可以将代码缩减为两行:

std::vector<int> firstHalf(original.begin(), original.begin() + original.size() / 2);
std::vector<int> secondHalf(original.begin() + original.size() / 2, original.end());

<强>原因:

push_back可以在元素数量增加时重新分配内存。 stl会在开始时分配足够的内存。

答案 1 :(得分:6)

我说这不是一种不好的做法,但这也不是很好的做法。

正如杰特的回答所指出的那样,可以将其简化为

std::vector<int> firstHalf(original.begin(), original.begin() + original.size() / 2);
std::vector<int> secondHalf(original.begin() + original.size() / 2, original.end());

我可能会尽量避免重新计算original.size()/2

std::size_t halfsize = original.size()/2;
std::vector<int> firstHalf(original.begin(), original.begin() + halfsize);
std::vector<int> secondHalf(original.begin() + halfsize, original.end());

或者,甚至,

std::vector<int>::const_iterator halfway = original.begin() + original.size()/2;

std::vector<int> firstHalf(original.begin(), halfway);
std::vector<int> secondHalf(halfway, original.end());

(在C ++ 11及更高版本中,halfsizehalfway的声明可以使用auto来确定类型。

这些是否更好(例如可读性)是非常主观的。

基本信息是,使用标准算法是一个好主意,其结果是更清晰的代码,并且有明显的等效性。添加一个额外的变量以避免重复的表达式有助于提高可读性。

如果由于某种原因你真的必须使用循环(例如,你所做的不仅仅是将向量的一部分复制到其他向量中),那么考虑一下;

  • 在多次调用reserve()
  • 之前使用push_back()
  • 在向量而不是数组下标
  • 上使用迭代器
  • 在循环之前预先计算重复使用的值(例如std::size_t halfsize = original.size()/2,而不是在循环内重复计算original.size()/2。如果original不是const,则特别相关,因为 - 根据您的循环的作用 - 编译器确定它的大小不会改变的可能性较小。
  • 在循环中使用标准算法,而不是实现嵌套循环。

答案 2 :(得分:2)

我会在两个单独的循环中执行此操作。这样,如果元素的数量不均匀并且循环非常简单,它也可以工作。

std::vector<int> firstHalf;
std::vector<int> secondHalf;

size_t middle = original.size()/2;

for (size_t i = 0; i < middle; i++)
{
    firstHalf.push_back(original[i]);
}

for (size_t i = middle; i < original.size(); i++)
{
    secondHalf.push_back(original[i]);
}

但我不会把你的原始代码称为坏习惯。

答案 3 :(得分:1)

为了通过空间局部性缓存友好,我会使用两个循环。在原始代码中,您在原始数组的各个部分之间来回跳转,索引大小为数组的一半。 以stride-1模式访问数组的元素要好得多。 此外,为子阵列保留空间并保存其他变量(如大小和计数)可能是值得的。

size_t size = original.size();
size_t mid_size = size / 2;

std::vector<int> firstHalf(mid_size);
std::vector<int> secondHalf((size - mid_size == mid_size) ? mid_size : mid_size + 1);

size_t i = 0;
for (; i < mid_size; i++) {
    firstHalf[i] = original[i];
}
for (; i < size; i++) {
    secondHalf[i - mid_size] = original[i];
}

Jett的回答非常好。

答案 4 :(得分:0)

对于像这样的简单代码,很容易理解发生了什么。但是对于更高级的代码(1000行),我相信大多数人宁愿把它分成2个for循环。

“效率更高”是什么意思?你看过汇编代码了吗?