【问题标题】:Conditional loop: variable vs function?条件循环:变量与函数?
【发布时间】:2019-10-31 10:37:49
【问题描述】:

是否有任何值得选择的理由,例如性能或安全性?

std::vector<std::string> some_vec{ "a","b","c"};

std::vector<std::string>::const_iterator iter = some_vec.begin();
std::vector<std::string>::const_iterator end = some_vec.end();

while( iter++ != end ){Do}

-

std::vector<std::string> some_vec{ "a","b","c"};

std::vector<std::string>::const_iterator iter = some_vec.begin();

while( iter++ != some_vec.end() ){Do}

【问题讨论】:

  • 嗯。 end = some_vec.begin() 这是错字吗?有什么理由不使用for (auto&amp;&amp; iter : some_ver)
  • 大多数编译器可能会将它们优化为相同。您必须分析您的具体情况,看看其中一个是否比另一个更快。
  • @LearnMore 即使更新Kamil Cuk 指出的错字,当向量为空时,两个代码sn-ps 都会调用未定义的行为。:)
  • @KamilCuk 是的,错字。已编辑!不能轻易使用 auto,因为每个循环都会迭代并处理来自 vec 的一对字符串。
  • @LearnMore 至于问题,例如,结束迭代器可以无效。所以如果在循环内改变了向量,那么第二个代码 sn-p 更安全。

标签: c++ loops conditional-statements


【解决方案1】:

第一个依赖于end 在循环期间不会失效:

// some_vec initialised with data!
std::vector<std::string> some_vec; 

std::vector<std::string>::const_iterator iter = some_vec.begin();
//std::vector<std::string>::const_iterator end = some_vec.end();

while( iter++ != some_vec.end() ){
    if (p(*iter)) iter = some_vec.insert(iter, "foo");
}

insert 可能会使所有迭代器无效,因此end 不能用于比较。

为了效率我不会太担心。如果some_vec.end() 将始终返回相同的迭代器,我希望编译器能够意识到这一点并执行适当的优化。

【讨论】:

    【解决方案2】:

    首先,while( iter++ != end ){Do} 是错误的。您最终将在循环体中有结束迭代器。解决这个问题,我们可以使用 quick-bench.com 来查看是否存在性能差异:

    #include <vector>
    
    static void test0(benchmark::State& state)
    {
        std::vector<std::string> some_vec{ "a", "b", "c" };
    
        for (auto _ : state)
        {
            auto iter = some_vec.cbegin();
            auto end = some_vec.cend();
            while (iter != end)
            {
                auto ch = (*iter++)[0];
                benchmark::DoNotOptimize(ch);
            }
        }
        benchmark::DoNotOptimize(some_vec);
    }
    // Register the function as a benchmark
    BENCHMARK(test0);
    
    static void test1(benchmark::State& state)
    {
        // Code before the loop is not measured
        std::vector<std::string> some_vec{ "a", "b", "c" };
        for (auto _ : state)
        {
            auto iter = some_vec.cbegin();
            while (iter != some_vec.cend())
            {
                auto ch = (*iter++)[0];
                benchmark::DoNotOptimize(ch);
            }
        }
        benchmark::DoNotOptimize(some_vec);
    }
    BENCHMARK(test1);
    

    在没有优化和 gcc 8.2 的情况下,test0 快 1.3 倍:

    优化级别 O3 test0 速度提高 1.1 倍:

    对于 Clang 7,它们大致相同:

    所以性能似乎不是问题,但如果最终插入器可以以某种方式失效,那么第二个版本会更安全。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-22
      • 2021-02-16
      • 2011-10-04
      • 1970-01-01
      相关资源
      最近更新 更多