【问题标题】:Looped push_back against resize() + iterator针对 resize() + 迭代器的循环 push_back
【发布时间】:2008-12-19 15:25:42
【问题描述】:

简单的问题;什么更好,为什么?



    out.resize( in.size() );
    T1::iterator outit = out.begin();
    for( inIt = in.begin() to end, ++inIt, ++outIt )
       *outit = *inIt
OR

    out.erase();
    for( inIt = in.begin() to end, ++inIt )
        out.push_back( inIt );


我假设 push_back 中隐含的内存分配值得避免,但要确保。

谢谢

编辑: 感谢 out = in 建议伙计们 ;)。我正在玩的实际代码是:


template//can't stop the browser ignoring th class T1, class T2 in angle brackets
bool asciihex( T1& out, const T2& in )
{
    //out.erase();
    out.resize( in.size() / 2 );
    if( std::distance( in.begin(), in.end() ) % 2 )//use distance rather than size to minimise the requirements on T2?
        return false;
    for( T2::const_iterator it = in.begin(); it != in.end(); it += 2 )
    {
        out.push_back(((( (*it > '9' ? *it - 0x07 : *it)  - 0x30)  '9' ? *(it+1) - 0x07 : *(it+1)) - 0x30) & 0x000f));
    }
    return true;
}

template
bool asciihex( T1& out, const T2& in )
{
    size_t size = in.size();
    if( size % 2 )//use distance rather than size to minimise the requirements on T2?
        return false;
    out.resize( size / 2 );
    T1::iterator outit = out.begin();
    for( T2::const_iterator it = in.begin(); it != in.end(); it += 2, ++outit )
    {
        *outit = ((( (*it > '9' ? *it - 0x07 : *it)  - 0x30)  '9' ? *(it+1) - 0x07 : *(it+1)) - 0x30) & 0x000f);
    }
    return true;
}

编辑:我已将 push_back 标记为答案,因为它似乎是共识,因此对遇到相同问题的其他人更有用。但是我最终使用了迭代器方法,因为我感兴趣的容器类之一不支持 push_back... 里程各不相同。

【问题讨论】:

  • 我希望这只是供您个人使用的玩具代码?

标签: c++ stl


【解决方案1】:

第二个,如果您担心多个扩展,请使用 out.reserve()。添加到向量的正确答案几乎总是 push_back 或 back_inserter,这样可以避免一些可能的问题(例如,异常保证、构造函数、写入末尾),而您必须使用其他方法注意这些问题。

【讨论】:

    【解决方案2】:

    第二个,只要你先预留合适的容量。

    我看到的一个问题(除了样式)是,在第一个问题中,如果你的复制分配抛出,你已经采取了一个应该给你强保证的操作,并用它来给出不保证。

    【讨论】:

      【解决方案3】:

      如果您关心保留 in,请执行以下操作:

      out = in;
      

      如果你不这样做,那么做:

      std::swap(out, in);
      

      如果 out 和 in 是不同类型的容器,那么试试这个:

      out.erase(out.begin(), out.end());
      // if it's a vector or other contiguous memory container, you'll want to reserve first
      // out.reserve(in.size());
      std::copy(in.begin(), in.end(), back_inserter(out));
      

      【讨论】:

        【解决方案4】:

        那么这有什么问题呢?

        out = in;
        

        你不认为那会是最好的行为吗?如果没有,那就糟了。

        另外,你的两个代码示例应该是

        out.resize( in.size() );
        T1::iterator outIt = out.begin();
        for( T1::iterator inIt = in.begin(); inIt != in.end(); ++inIt, ++outIt )
           *outIt = *inIt;
        

        out.erase(out.begin(), out.end());
        for( T1::iterator inIt = in.begin(); inIt != in.end(); ++inIt )
            out.push_back( *inIt );
        

        【讨论】:

        • 抱歉,我简化了示例并在 for 循环中使用了一些伪代码
        【解决方案5】:

        如果您正在处理整数或双精度值等简单值,则调整大小并设置或保留和 push_back 将无关紧要(性能方面)。

        如果您正在处理具有重要构造函数的更复杂的对象,最好使用第二个基于 push_back 的方法。

        如果您的对象没有有意义的默认构造函数,那么 push_back 方法是唯一有效的技术。

        【讨论】:

        • 好,明确的答案。可能值得强调的是,reserve() 不在原始问题中。这就是答案的关键。
        【解决方案6】:

        与在调整大小的向量上使用 [] 运算符相比,我在基于 push_back 的解决方案中的性能更差。造成差异的原因是每次执行push_back 时检查向量是否需要扩展其容量的开销。

        更糟糕的是编译器决定它不能内联对push_back 的调用,但它确实将保留逻辑内联到push_back 方法中。这给了函数调用的开销,并且调用的函数不必要的大。即使经过一些 force_inline 按摩,它也没有基于 [] 运算符的循环快。

        基于迭代器或 [] 运算符的循环除了写入值外不会做任何事情,至少在使用简单类型时不会。如果使用更高级的类型,则在调整向量大小时默认构造函数的成本可能会破坏潜在的胜利。

        无论如何,如果您的程序大部分时间都花在这些循环中,我绝对认为您应该对不同的解决方案进行基准测试,看看使用其中一种解决方案是否可以获得任何性能。如果您没有在您描述的功能上花费大量执行时间,那么您不应该关心这篇文章:)

        【讨论】:

          【解决方案7】:

          我更喜欢 push_back 而不是数组赋值,因为 push_back 可以在有或没有随机访问迭代器的情况下工作。数组分配需要它们。如果您现在强制使用 randomaccessiterators,那么将来您将无法轻松更改容器。当然,为了避免调整大小问题,您调用 vector::capacity 而不是调整大小。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-10-24
            • 2012-07-20
            • 2019-04-23
            • 2020-12-04
            • 2016-01-02
            • 1970-01-01
            • 1970-01-01
            • 2013-11-19
            相关资源
            最近更新 更多