5

有没有做某事两次的常见习语,如以下情况?

    for ( int i = 0; i < num_pairs; i++ ) {
        cards.push_back( Card(i) );
        cards.push_back( Card(i) );
    }

我觉得有一种比引入一个从 0 到 1 计数的新循环变量更清晰的方法,特别是因为它除了计数之外不使用。

    for ( int i = 0; i < num_pairs; i++ )
        for ( int j = 0; j < 2; j++ )
            cards.push_back( Card(i) );

Card只是我编的一些课程,与问题无关。)

4

5 回答 5

10

您可能想fill_n<algorithm>

for ( int i = 0; i < num_pairs; i++ )
    std::fill_n(std::back_inserter(cards), 2, Card(i));
于 2012-05-22T19:29:03.867 回答
6

就我个人而言,我会保持现状。它看起来很干净,很容易理解,而且可读性很强。只需发表评论,说明您为什么要这样做两次(但无论如何您都会这样做)。

于 2012-05-22T19:29:49.483 回答
5

我有几个建议。我的建议见最后一个:

  1. 在我看来节拍:insert(it, N, value)std::fill_n

    for ( int i = 0; i < num_pairs; i++ ) {
        cards.insert(cards.end(), 2, Card(i) );
    }
    
  2. 如果顺序不重要,您可以只生成一次卡片,然后复制

    std::copy(cards.begin(), cards.end(), std::back_inserter(cards));
    
  3. 使用脏 lambda 和整数除法技巧。警告这具有过早优化的标志:无缘无故降低可读性。

    std::vector<Card> cards(num_pairs * 2);
    int i = 0;
    std::generate_n(cards.begin(), num_pairs, [&i] () { return Card(i++/2); });
    

    (假设Carddefault-constructible。如果不是,使用cards.back_inserter()

  4. 我的推荐

    以下在性能和意图表达方面均胜出:

    std::vector<Card> cards;
    cards.reserve(num_pairs*2);
    for (int i = 0; i < num_pairs; ++i)
    {
        cards.emplace_back(i);
        cards.emplace_back(i);
    }
    
于 2012-05-22T21:10:13.560 回答
1

使用将内部循环扩展为语句是正确的,因为仅使用另一个循环 2 次迭代对性能不利。由于频繁jumps,第二个(嵌套循环)将执行缓慢。是否会有任何明显的差异完全取决于num_pairs.

所以第一个对性能更好(无论增益可能有多小)。这种扩展循环loop unwinding/unrolling在编译器的术语中被称为。但是,该术语不在编程级别使用,因为通常只有编译器这样做才能使代码更快。Idioms肯定design notions会帮助程序员编写更好、更高效的代码并更好地理解语言。

于 2012-05-22T19:45:37.717 回答
1

如果您想经常这样做,请编写一个小实用函数:

template<class F>
void repeat(unsigned times, F callback) {
  while (times--) callback();
}

// ...

for (int i = 0; i < num_pairs; i++) {
  repeat(2, [&] { cards.push_back(Card(i)); });
}

我在Ideone上写了一个例子。


您的第一种方法可能会让您的代码的未来读者感到困惑。他们可能会认为代码偶然出现了两次。使用这样的函数可以避免这种混乱。

即使> 0,性能损失也将非常小,因为编译器可能会内联函数并完全优化小times'的循环。如果您担心性能,请先进行基准测试。

于 2012-05-22T19:46:26.807 回答