简体   繁体   中英

How to run an infinite loop?

I want to run some code over and over again basically forever, but I don't want my computer to run out of memory or something like that. So I was wondering how i could do that in c++? I did this.

for (int i = 0; i <= 2; i++) {
    if (i == 1) {i = 0;}
    //My code here
}

I was wondering if this would do something bad to my computer?

while(true)
{
    //Your code here
}

If you prefer the for syntax:

for ( ; ; ) {
    // do stuff.
}

An infinite loop will not cause your computer to run out of memory if you aren't allocating memory without freeing them.

There are a few common ways of writing an infinite loop.

for (;;) {
   // do something over an over again
}

while (true) {
   // do something over an over again
}

By itself, an infinite loop doesn't cause the program to run out of memory. But if you allocate memory and forget to deallocate it, that would cause memory leak. In light that, the following code would be alright:

YourClass* p;
for (;;) {
    p = new YourClass();    // every time the loop runs, a new instance of the class is created
    // [do something useful with the object]
    delete p;   // clean-up: deallocate the object.
}

But this would cause a memory leak:

YourClass* p;
for (;;) {
    p = new YourClass();    // every time the loop runs, a new instance of the class is created
    // [do something useful with the object]
    // oups... forgot to deallocate the object.
}

Infinite Loops are great if you know how to manage them. Even with an infinite loop you would still want a possible exit condition. If you are designing infinite loops as to where there are no possible exits out of the loop based on its dataset, the safest thing to do is to keep track of the instance of your application object and its current state and when its state changes to exit, then any infinite loop running across any thread can be tested against this and will automatically exit when available to do so to prevent your computer from hanging to where you would need to do a hard reset or shutdown. Just make sure that all of your memory will be cleaned up as this event is triggered. Now if you have multiple threads running either in parallel or asynchronous and they are managed by a queue or event trigger list then it still may take time for every loop to exit depending on which loops you designate to be in a CRITICAL_SECTION.

class Application {
public:
    enum ApplicationState {
        APPLICATION_RUNNING = 0,
        APPLICATION_PAUSED,  // Out of Focus or Paused If In A Timed Situation
        APPLICATION_EXIT,
    };
private:
    // Member Variables Such As Window Handle, Time Etc.,
    ApplicationState m_state;
public:
    Application();
    // virtual ~Application(); // Default Okay - Use Virtual If Using Inheritance
    ApplicationState getState() const { return m_state; }

    bool start() { m_sate = APPLICATION_RUNNING; return true; }
    bool pause() { m_state = APPLICATION_PAUSED; return true; } 
    // resume may keep track of time if the application uses a timer.
    // This is what makes it different than start() where the timer
    // in start() would be initialized to 0. And the last time before
    // paused was trigger would be saved, and then reset as new starting
    // time for your timer or counter. 
    bool resume() { m_state = APPLICATION_RUNNING; return true; }      
    bool exit(); { m_state = APPLICATION_EXIT;  return false; }

};

int main() {
    Application app;
    app.start();

    // One Type Of Infinite Loop, with a safety net.
    while ( !app.exit() ) {
        // do some work
    }

    // Another Type Similar But Different
    while ( app.getState() == Application::APPLICATION_RUNNING ) {
      // do some work  
    } 

    // A Third Type
    while ( true ) {
       switch( app.getState() ) {
           case Application::APPLICATION_RUNNING {
               app.start(); // If Not Done Above Outside of Loop
               // Do Some Work
               break;
           }
           case Application::APPLICATION_PAUSE {
               // Wait Till You Has Focus Or Continues
               break;
           }
           case Application::APPLICATION_EXIT {
               // Change The Application State
               app.pause();
               break;
           }
           default: {
               // ErrorHandling Throw An Exception Etc.
           }

        } // switch
    } while

    return 0;
}

Some Of These Types of methods you may not necessarily see in the main.cpp. You would see these types of loops within your application class that are done privately and invoked publicly so that your main.cpp would look cleaner as such:

main.cpp

#include "Application.h"

int main() {

    try {
        // Initialize Loggers, Settings, Process - Thread Blockers etc.

        // Handle Input Arguements

        // Give The Main Thread Application, Window Handle, Mutex etc, A Unique Name
        const std::string strApplicationName( "My Application" );
        Application app( strApplicationName );
        app.start();

        }

    } catch( YourTypes& e ) {
        // Print Errors To Either File Or Console
        return RETURN_ERROR; 
    } catch ( ... ) {  // Default Types
        // Print Errors To Either File Or Console 
        return RETURN_ERROR;     
    } 

    return RETURN_OK; // return 0;
}

This way your main is clean and easy to follow and your loops are happening within your application class object. This way you can still have infinite loops running as long as the application is running. Now if you are writing drivers, file or memory monitors, malware or antivirus dlls or processes that run in windows background then you may not want this behavior, but since these processes run in the background of windows it is still safe to say yes if this process or executable goes out of scope and ends we still want to exit all loops safely and clean up all memory!

The Paradigm here is to safely and efficiently manage a well structured application. The reason I used this as an example is that when you get away from writing event driven or data driven types of applications and are working with any kind of game development this is an appropriate model to follow. The only difference instead of naming your class as Application, you would more than likely name it Game and have Game inherit from an Engine class. This way the code is re-usable to build and develop multiple games. It is generic enough to handle all graphics, sounds, fonts, rendering etc., and this Engine class will be abstract where this base class can not be instantiated on its own, you would have to create the Game class object as an inherited class that can be instantiated. You may also want to have the Engine class inherit from a Singleton class so that you can only ever have one instance of a Game : Engine object. The Game class would then be responsible for all of the assets being loaded, level designs being loaded, which fonts & sounds to be loaded, which animations to load, etc., things that are unique to this game. This makes it very modular. This setup would also require the Engine to construct multiple Manager type classes that rely heavily on templates.

This following is not my work, but is a project I've been working on and all credit goes to Marek A. Krzeminski, MASc at http://www.marekknows.com This excerpt shows the main.cpp file.

// Version: 1.0
// Copyright (c) 2012 by Marek A. Krzeminski, MASc
// Marek@MarekKnows.com

#include "stdafx.h"
#include "BuildConfig.h"
#include "Settings.h"
#include "BlockProcess.h"
#include "Logger.h"
#include "Utility.h"

#include "Game.h"

// ----------------------------------------------------------------------------
// _tmain()
// Main Entry Point Into Application
int _tmain( int iNumArguments, _TCHAR* pArgumentText[] ) {
    using namespace vmk;

    try {
        // Test If Engine Is Supported By This Compiler
        Utility::testPlatform();

        Logger logger( "logger.txt" );
        Settings settings;

        // Prevent Starting Game Multiple Times At Once
        BlockProcess processBlocker( settings.getNameAndVersion() );
        if ( processBlocker.isBlocked() ) {
            std::ostringstream strStream;
            strStream << settings.getNameAndVersion() << " is already running in another window" << std::endl;
            throw ExceptionHandler( strStream, false );
        }

        // Handle Input Arguments
        bool bShowHelp = false;
        for ( int i = 1; i < iNumArguments; ++i ) {
            std::ostringstream strStream;
            strStream << "Input Argument " << i << ": " << pArgumentText[i];

            std::string strArgument( Utility::toLower( std::string( pArgumentText[i] ) ) );

            if ( strArgument.compare( "/?" ) == 0 || strArgument.compare( "help" ) == 0 ) {
                bShowHelp = true;
            } else if ( strArgument.compare( "window" ) == 0 ) {
                settings.setWindowDisplayMode( true );
            } else if ( strArgument.compare( "debug_memory" ) == 0 ) {
                settings.setDebugLogging( settings.getDebugLogging() | Settings::DEBUG_MEMORY );
            } else if ( strArgument.compare( "seed" ) == 0 ) {
                // Need Next Argument To Know Which Seed Value To Use
                bool bError     = false;
                unsigned uSeedValue = 0;
                if ( i + 1 < iNumArguments ) {
                    uSeedValue = Utility::convertToUnsigned( std::string( pArgumentText[i+1] ) );
                    if ( uSeedValue == 0 ) {
                        bError = true;
                    } else {
                        settings.setRandomNumberSeed( uSeedValue );
                        i++; // Move Argument Counter Past Seed Value
                    }
                } else {
                    bError = true;
                }

                if ( bError ) {
                    // Missing Argument For Seed Value
                    std::cout << " <- Missing Seed Value After This Argument";
                } else {
                    // Display Seed Value To Use
                    strStream << " " << uSeedValue;
                }           
            } else {
                strStream << " <- Unrecognized input argument";
            }

            Logger::log( strStream, Logger::TYPE_CONSOLE );
        }

        if ( bShowHelp ) {
            std::ostringstream strStream;
            strStream << std::endl
                      << settings.getNameAndVersion() << " command line arguments:" << std::endl
                      << "  seed nnn     | Supply seed value (nnn) to use in random number generator" << std::endl
                      << "  window       | Run the program in a window rather then full screen" << std::endl
                      << "  debug_memory | Log extra messages when objects are allocated in memory" << std::endl
                      << std::endl;
            Logger::log( strStream, Logger::TYPE_CONSOLE );

        } else {
            // Run The Game Here
            Game game;
            game.start();

        } 
    } catch( ExceptionHandler& e ) {
        std::cout << "Exception Thrown: " << e.getMessage() << std::endl;
        Utility::pressAnyKeyToQuit();
        return RETURN_ERROR;
    } catch( ... ) {
        std::cout << __FUNCTION__ << " Caught Unknown Exception" << std::endl;
        Utility::pressAnyKeyToQuit();
        return RETURN_ERROR;
    }

    return RETURN_OK;

 } // _tmain

As you can see there is no visible infinite while or for loop visible here since this type of algorithm is nested deep within the Game - Engine object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM