C/C++——++i、i+=1、i++之间的区别(附在学习boost时遇到的例子)

来源:互联网 发布:哪里有卖校管家软件 编辑:程序博客网 时间:2024/06/05 11:42

首先,对于++i和i++的区别是早就认识到了,效率肯定是前置++i更高,因为后者还需要产生临时变量。

查了相关资料

其实这个问题可以从三个角度去分析:语言规范,编译器实现,CPU支持。首先从语言规范上来讲;前置++和后置++是不等价的,前置++在规范中明确指出 和+=组合操作符是等价的,但和E = E+1;这样的赋值操作不等价,因为后者对操作数E需要进行两次求值,而+=组合操作符只进行一次求值。后置++表示操作数作为结果值被获取之后操作数的 原值再进行更新。 聪明的编译器可以根据应用场景进行优化(标准不规定相关优化的手段,由编译器自决),但不能过度依赖这种优化,因为编译器还是不如人聪明,而且复杂的表达式也不一定可以优化掉。从 CPU的角度上来讲CPU支持什么样的指令集是绝对决定了相应操作符计算效率。在嵌入式开发中不同的CPU之间的差异就大了。比如说PowerPC CPU就没有直接可以对应后缀++的t自增指令,某些版本的ARM CPU没有任何自增指令(无论是前置还是后置式的)。因此无论从CPU支持来讲还是编译器优化来看前置++肯定是高效的,后置++的即时CPU和编译器优化都支持也不能比前置++更高效,在使用的时候应该尽量使用前置++。C/C++提供这么多操作符是因为它是最接近底层的高级语言,它需要尽可能实现CPU对应 指令的高级实现进而为性能优化提供选择。而其它多数高级语言不会给你选择的权利。

下面是标准中的相关信息:

The value of the operand of the prefix ++ operator is incremented. The result is the new
value of the operand after incrementation. The expression ++E is equivalent to (E+=1).
See the discussions of additive operators and compound assignment for information on
constraints, types, side effects, and conversions and the effects of operations on pointers.

The result of the postfix ++ operator is the value of the operand. After the result is
obtained, the value of the operand is incremented. (That is, the value 1 of the appropriate
type is added to it.) See the discussions of additive operators and compound assignment
for information on constraints, types, and conversions and the effects of operations on
pointers. The side effect of updating the stored

A compound assignment of the form E1 op= E2 differs from the simple assignment
expression E1 = E1 op (E2) only in that the lvalue E1 is evaluated only once.

来看具体例子

这个是我写的cpp文件

#include <boost\progress.hpp>#include <iostream>#include <vector>#include <fstream>using namespace boost;using namespace std;int main(){    vector<string> v(100);    ofstream fs("./test.txt");    //声明一个progress_display对象,基数是v的大小    progress_display pd(v.size());    //开始迭代遍历向量,处理字符串,写入文件    for (auto& x : v){        fs << x << endl;        ++pd;    }    return 0;}

下面是progress_display.hpp

//  boost progress.hpp header file  ------------------------------------------////  Copyright Beman Dawes 1994-99.  Distributed under the Boost//  Software License, Version 1.0. (See accompanying file//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)//  See http://www.boost.org/libs/timer for documentation.//  Revision History//   1 Dec 01  Add leading progress display strings (suggested by Toon Knapen)//  20 May 01  Introduce several static_casts<> to eliminate warning messages//             (Fixed by Beman, reported by Herve Bronnimann)//  12 Jan 01  Change to inline implementation to allow use without library//             builds. See docs for more rationale. (Beman Dawes) //  22 Jul 99  Name changed to .hpp//  16 Jul 99  Second beta//   6 Jul 99  Initial boost version#ifndef BOOST_PROGRESS_HPP#define BOOST_PROGRESS_HPP#include <boost/timer.hpp>#include <boost/noncopyable.hpp>#include <boost/cstdint.hpp>  // for uintmax_t#include <iostream>           // for ostream, cout, etc#include <string>             // for stringnamespace boost {//  progress_timer  ----------------------------------------------------------////  A progress_timer behaves like a timer except that the destructor displays//  an elapsed time message at an appropriate place in an appropriate form.class progress_timer : public timer, private noncopyable{ public:  explicit progress_timer( std::ostream & os = std::cout )     // os is hint; implementation may ignore, particularly in embedded systems     : timer(), noncopyable(), m_os(os) {}  ~progress_timer()  {  //  A) Throwing an exception from a destructor is a Bad Thing.  //  B) The progress_timer destructor does output which may throw.  //  C) A progress_timer is usually not critical to the application.  //  Therefore, wrap the I/O in a try block, catch and ignore all exceptions.    try    {      // use istream instead of ios_base to workaround GNU problem (Greg Chicares)      std::istream::fmtflags old_flags = m_os.setf( std::istream::fixed,                                                   std::istream::floatfield );      std::streamsize old_prec = m_os.precision( 2 );      m_os << elapsed() << " s\n" // "s" is System International d'Unites std                        << std::endl;      m_os.flags( old_flags );      m_os.precision( old_prec );    }    catch (...) {} // eat any exceptions  } // ~progress_timer private:  std::ostream & m_os;};//  progress_display  --------------------------------------------------------////  progress_display displays an appropriate indication of //  progress at an appropriate place in an appropriate form.// NOTE: (Jan 12, 2001) Tried to change unsigned long to boost::uintmax_t, but// found some compilers couldn't handle the required conversion to double.// Reverted to unsigned long until the compilers catch up. class progress_display : private noncopyable{ public:  explicit progress_display( unsigned long expected_count_,                             std::ostream & os = std::cout,                             const std::string & s1 = "\n", //leading strings                             const std::string & s2 = "",                             const std::string & s3 = "" )   // os is hint; implementation may ignore, particularly in embedded systems   : noncopyable(), m_os(os), m_s1(s1), m_s2(s2), m_s3(s3) { restart(expected_count_); }  void           restart( unsigned long expected_count_ )  //  Effects: display appropriate scale  //  Postconditions: count()==0, expected_count()==expected_count_  {    _count = _next_tic_count = _tic = 0;    _expected_count = expected_count_;    m_os << m_s1 << "0%   10   20   30   40   50   60   70   80   90   100%\n"         << m_s2 << "|----|----|----|----|----|----|----|----|----|----|"         << std::endl  // endl implies flush, which ensures display         << m_s3;    if ( !_expected_count ) _expected_count = 1;  // prevent divide by zero  } // restart  unsigned long  operator+=( unsigned long increment )  //  Effects: Display appropriate progress tic if needed.  //  Postconditions: count()== original count() + increment  //  Returns: count().  {    if ( (_count += increment) >= _next_tic_count ) { display_tic(); }    return _count;  }  unsigned long  operator++()           { return operator+=( 1 ); }  unsigned long  count() const          { return _count; }  unsigned long  expected_count() const { return _expected_count; }  private:  std::ostream &     m_os;  // may not be present in all imps  const std::string  m_s1;  // string is more general, safer than   const std::string  m_s2;  //  const char *, and efficiency or size are  const std::string  m_s3;  //  not issues  unsigned long _count, _expected_count, _next_tic_count;  unsigned int  _tic;  void display_tic()  {    // use of floating point ensures that both large and small counts    // work correctly.  static_cast<>() is also used several places    // to suppress spurious compiler warnings.     unsigned int tics_needed = static_cast<unsigned int>((static_cast<double>(_count)        / static_cast<double>(_expected_count)) * 50.0);    do { m_os << '*' << std::flush; } while ( ++_tic < tics_needed );    _next_tic_count =       static_cast<unsigned long>((_tic/50.0) * static_cast<double>(_expected_count));    if ( _count == _expected_count ) {      if ( _tic < 51 ) m_os << '*';      m_os << std::endl;      }  } // display_tic};} // namespace boost#endif  // BOOST_PROGRESS_HPP
原创粉丝点击