Two Types of Line Breaks in C++

There are two types of line breaks in C++, however, some tutorials ignored the trivial difference between the two. As a result, novices made great mistakes when using them, especially in File IO.

Source Code Analysis

std::cout – operator<<

C++
template <class _Traits>
basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>& _Ostr, char _Ch) {
    // insert a char into char stream
    using _Elem = char;
    using _Myos = basic_ostream<_Elem, _Traits>;

    ios_base::iostate _State = ios_base::goodbit;
    const typename _Myos::sentry _Ok(_Ostr);

    if (_Ok) { // state okay, insert
    
    ...<Omitted>

std::endl – operator<<

C++
template <class _Elem, class _Traits>
basic_ostream<_Elem, _Traits>& __CLRCALL_OR_CDECL endl(
    basic_ostream<_Elem, _Traits>& _Ostr) { // insert newline and flush stream
    _Ostr.put(_Ostr.widen('\n'));
    _Ostr.flush();
    return _Ostr;
}




  • Note the annotation “insert newline and flush”, which means std::endl will not only insert a new line but flush the buffer as well, whereas, inserting \n will not automatically flush the buffers.

IO Speed Test

Standard IO

Debug (O0)Release (O2)
std::endl15.466999 sec14.670679 sec
\n20.866858 sec20.149517 sec
  • At first, ‘\n’ is faster than std::endl, however, the std::endl become faster with the increase of loop circles.
C++
#include <iostream>
#include <chrono>
#include <format>

namespace FU
{
    class LoopTimer
    {
    public:
        LoopTimer() :currentTime{ std::chrono::high_resolution_clock::now() } {};
        LoopTimer(const LoopTimer& copy) = delete;
        LoopTimer& operator=(const LoopTimer& another) = delete;

    public:
        float getDuration_sec()
        {
            auto samplingPoint = std::chrono::high_resolution_clock::now();
            float duration = std::chrono::duration<float, std::chrono::seconds::period>(samplingPoint - this->currentTime).count();
            this->currentTime = samplingPoint;
            return duration;
        }
    private:
        std::chrono::steady_clock::time_point currentTime;
    };
}// namespace FU

int main(int argc, char* argv[])
{
    static float t1, t2;
    static FU::LoopTimer timer{};
    for (int i = 0; i < std::numeric_limits<short>::max(); ++i)
    {
        std::cout << i << '\n';
    }
    t1 = timer.getDuration_sec();
    for (int i = 0; i < std::numeric_limits<short>::max(); ++i)
    {
        std::cout << i << std::endl;
    }
    t2 = timer.getDuration_sec();
    std::cout << std::format("Time consumed ('\\n' with 02) = {} sec\n", t1);
    std::cout << std::format("Time consumed (std::endl with 02) = {} sec\n", t2);
    return EXIT_SUCCESS;
}









File IO Test

Debug (O0)Release (O2)
std::endl0.4009735 sec0.2301016 sec
\n0.1254081 sec0.0145921 sec
  • Obviously, ‘\n’ is extremely faster than std::endl while you are doing File IO because flush data to file is very slow.
C++
#include <iostream>
#include <chrono>
#include <format>
#include <fstream>

namespace FU
{
    class LoopTimer
    {
    public:
        LoopTimer() :currentTime{ std::chrono::high_resolution_clock::now() } {};
        LoopTimer(const LoopTimer& copy) = delete;
        LoopTimer& operator=(const LoopTimer& another) = delete;

    public:
        float getDuration_sec()
        {
            auto samplingPoint = std::chrono::high_resolution_clock::now();
            float duration = std::chrono::duration<float, std::chrono::seconds::period>(samplingPoint - this->currentTime).count();
            this->currentTime = samplingPoint;
            return duration;
        }
    private:
        std::chrono::steady_clock::time_point currentTime;
    };
}// namespace FU

int main(int argc, char* argv[])
{
    static float t1, t2;
    static FU::LoopTimer timer{};

    std::ofstream outputA{ "outputA.txt" };
    std::ofstream outputB{ "outputB.txt" };

    timer.getDuration_sec(); // Refresh

    for (int i = 0; i < std::numeric_limits<short>::max(); ++i)
    {
        outputA << i << '\n';
    }
    t1 = timer.getDuration_sec();
    for (int i = 0; i < std::numeric_limits<short>::max(); ++i)
    {
        outputB << i << std::endl;
    }
    t2 = timer.getDuration_sec();
    std::cout << std::format("Time consumed ('\\n' with Debug) = {} sec\n", t1);
    std::cout << std::format("Time consumed (std::endl with Debug) = {} sec\n", t2);
    
    outputA.close();
    outputB.close();
    return EXIT_SUCCESS;
}

Conclusion

  • Flush(std::endl) will impact the File IO performance; but has no or slight impact on Standard IO.

Leave a Reply

Your email address will not be published. Required fields are marked *