Thread: Will my memory leak? --school project

  1. #1
    Registered User
    Join Date
    Aug 2009
    Posts
    34

    Will my memory leak? --school project

    I am wondering if the class I have designed will leak memory. Does my destructor do all neccesary clean up? I appreciate any help you can offer. I attempted to find a easy to use leak detector, but couldn't. I thought someone may be able to tell just by seeing my destructor and data members. Please find code for .h and .cpp file below.

    Thanks.

    Code:
    #include <string>
    #include <iostream>
    using std::string;
    
    #include "VendingMachine.h"
    
    Project1::VendingMachine::VendingMachine(
          ostream &statusPanelStream,
    		const vector<string> &productNames,
    		const vector<unsigned> &productPrices,
    		unsigned maxProductsPerRack)
    	: statusPanel(statusPanelStream), unspentMoneyCents(0)
    { 
       for( unsigned x = 0; x < productNames.size(); ++x)
       {
       productRacks.push_back(new ProductRack(productNames.at(x), maxProductsPerRack, deliveryChute, productPrices.at(x)));
       productButtons.push_back(new ProductButton(productNames.at(x), *productRacks.back()));
       } 
    }
    
    Project1::VendingMachine::~VendingMachine()
    {
       while (productButtons.size() > 0)
       {
          delete productButtons.back();
          productButtons.pop_back();
       }
       
       while (productRacks.size() > 0)
       {
          delete productRacks.back();
          productRacks.pop_back();
       }
    
       while (coins.size() > 0)
       {
          delete coins.back();
          coins.pop_back();
       }
    }
    
    bool
    Project1::VendingMachine::insertCoin(Coin *pCoin)                    
    {
       if(pCoin->getValueCents() != 0)
       {
          unspentMoneyCents += pCoin->getValueCents();                   //updates unspentmoney
          coins.push_back(pCoin);                                        //adds coin to vector should be used in later function?
          return true;
       }
       else
       {
          statusPanel.displayMessage(StatusPanel::MESSAGECODE_BAD_COIN);
          return false;
       }
    }
    
    void
    Project1::VendingMachine::pressSelectButton(string buttonLabel) 
    {
          unsigned x, y;
          for( x = 0, y = 0; x < productButtons.size(); ++x ) 
             if(productRacks.at(x)->isCompatibleProduct(buttonLabel))
                y = x;
                if(productRacks.at(y)->isCompatibleProduct(buttonLabel) == 0)
                   statusPanel.displayMessage(StatusPanel::MESSAGECODE_WRONG_BUTTON);
                else if(unspentMoneyCents < productRacks.at(y)->getProductPriceCents())
                   statusPanel.displayMessage(StatusPanel::MESSAGECODE_INSUFFICIENT_MONEY);
                else if(productRacks.at(y)->isEmpty() != 0)
                   statusPanel.displayMessage(StatusPanel::MESSAGECODE_SOLD_OUT);
                else if(deliveryChute.containsProduct() != 0)
                   statusPanel.displayMessage(StatusPanel::MESSAGECODE_CHUTE_FULL);
                else productButtons.at(y)->press();
                
    }
               
    Project1::Product *
    Project1::VendingMachine::retrieveProduct()                  
    {
          return deliveryChute.retrieveProduct();
    }
    
    bool
    Project1::VendingMachine::addProduct(Product *pProduct)
    {
       unsigned x;
       for( x = 0; x < productRacks.size(); ++x )
          if(productRacks.at(x)->isCompatibleProduct(pProduct->getName()))
          {
             if(productRacks.at(x)->addProduct(pProduct) != 0)
                return true;
             else
             {
                statusPanel.displayMessage(StatusPanel::MESSAGECODE_RACK_IS_FULL);
                return false;
             }
          }
       statusPanel.displayMessage(StatusPanel::MESSAGECODE_NO_RACK_FOR_PRODUCT);
       return false;
    }
    
    unsigned
    Project1::VendingMachine::getProductCount(string productName) const
    {
       int x;
       for(x = 0; x != productButtons.size() && productName.compare(productButtons.at(x)->getLabel()) != 0; ++x)
          ;
       return productRacks.at(x)->getNumProductsInRack();
    }
    
    unsigned
    Project1::VendingMachine::countTill() const
    {
       unsigned x, total = 0;
       for(x = 0; x < coins.size(); ++x)
          total += coins.at(x)->getValueCents();
       return total;
    }
    
    vector<Project1::Coin *>
    Project1::VendingMachine::emptyCoinBox()
    {
       vector<Coin *> tempCoinVector;
       for( unsigned x = coins.size(); x > 0; x-- )
       {
          Coin *tempCoin = coins.back();
          tempCoinVector.push_back(tempCoin);
          coins.pop_back();
       }
       return tempCoinVector;
    }
    And my interface with data members...

    Code:
    #ifndef PROJECT1_VENDINGMACHINE_H
    #define PROJECT1_VENDINGMACHINE_H
    
    #include <ostream>
    using std::ostream;
    
    #include <string>
    using std::string;
    
    #include <vector>
    using std::vector;
    
    #include "Coin.h"
    #include "DeliveryChute.h"
    #include "Product.h"
    #include "ProductButton.h"
    #include "ProductRack.h"
    #include "StatusPanel.h"
    
    namespace Project1
    {
       //==================================================================================================================
       // SUMMARY
       //    A vending machine containing products (soft drinks).  Two types of users interact with a vending machine,
       //    customers and service professionals.
       // 
       //    A customer can insert coins into a coin slot, press any of the buttons to cause the appropriate product
       //    to be delivered if enough money has been inserted, retrieve a product from a delivery chute, and view
       //    a status panel to see diagnostic messages (e.g. not enough money was entered when a button was pressed,
       //    a button was pressed and the vending machine is out of the associated product, etc.).
       // 
       //    A service professional can add products to the vending machine, obtain a count of the number of products of
       //    a given type left in the machine, obtain a sum of the total money in the machine, and retrieve the
       //    money from the machine.
       // 
       // RESOURCES
       //    A vending machine owns (i.e. is responsible for freeing the memory of) all products and coins that are
       //    inserted into the machine.  The vending machine relinquishes ownership of all products and coins that are
       //    removed from the vending machine.
       //==================================================================================================================
       class VendingMachine
       {
       public:
          //---------------------------------------------------------------------------------------------------------------
          // SUMMARY
          //    Constructor.  Create an empty vending machine (containing no products or coins).  The vending machine will
          //    be initialized to contain one product button wired to a product rack for each entry in the productNames
          //    list.  Each of these racks will have a capacity equal to maxProductsPerRack.  The products stored in each
          //    rack will be priced according to the corresponding entry in the productPrices list (e.g. the products
          //    in the rack for productNames[0] will have the price given by productPrices[0]).  The vending machine
          //    will output all error messages to a status panel initialized to the statusPanelStream.
          //
          // RESOURCES
          //    The vending machine will be initialized to not own any product or coins.
          //
          // PARAMETERS
          //    statusPanelStream
          //       The ostream to which error messages will be written during the operation of the vending machine.
          //    productNames
          //       The names of all products that the vending machine can hold.  A product rack will be created
          //       for each of these products.
          //    productPrices
          //       The prices of the products stored within the vending machine.  Each entry in this list corresponds
          //       to the product at the same index in the productNames list.
          //    maxProductsPerRack
          //       The maximum number of each product specified by productNames that may be present in the vending
          //       machine.
          //
          // RETURNS
          //    Nothing
          //---------------------------------------------------------------------------------------------------------------
          VendingMachine(
             ostream &statusPanelStream,
             const vector<string> &productNames,
             const vector<unsigned> &productPrices,
             unsigned maxProductsPerRack);
    
          //---------------------------------------------------------------------------------------------------------------
          // SUMMARY
          //    Destructor.  Destroy the vending machine.
          //
          // RESOURCES
          //    All owned products and coins are freed.
          //
          // PARAMETERS
          //    None
          //
          // RETURNS
          //    Nothing
          //---------------------------------------------------------------------------------------------------------------
          ~VendingMachine();
          
          //---------------------------------------------------------------------------------------------------------------
          // SUMMARY
          //    Insert a coin into the vending machine coin slot; this increases the current balance that can be used
          //    to purchase products.  If the coin is invalid (a wooden nickel) the coin will be rejected.
          //
          // RESOURCES
          //    The vending machine takes ownership of the coin if and only if the coin is accepted.
          //
          // PARAMETERS
          //    pCoin
          //       The coin to be inserted into the vending machine.
          //
          // RETURNS
          //    Whether the coin was successfully inserted into the vending machine.
          //
          // OUTPUTS
          //    StatusPanel::MESSAGECODE_BAD_COIN
          //       Output if a coin is inserted that this vending machine does not accept.
          //---------------------------------------------------------------------------------------------------------------
          bool insertCoin(Coin *pCoin);
    
          //---------------------------------------------------------------------------------------------------------------
          // SUMMARY
          //    Press the button with the given label; if a valid button was pressed, enough money has been previously
          //    inserted into the coin slot, the vending machine is not out of the associated product, and the delivery
          //    chute is empty then the current balance is reduced by the cost of the product and the next available
          //    product is dropped into the delivery chute.
          //
          // RESOURCES
          //    None
          //
          // PARAMETERS
          //    buttonLabel
          //       The name of the button to press.
          //
          // RETURNS
          //    Nothing
          //
          // OUTPUTS
          //    StatusPanel::MESSAGECODE_SOLD_OUT
          //       Output if there are no products in the product rack associated with the button was pressed.
          //    StatusPanel::MESSAGECODE_INSUFFICIENT_MONEY
          //       Output if the price of the product associated with the button that was pressed is greater than the
          //       current balance of money that has been inserted into the vending machine.
          //    StatusPanel::MESSAGECODE_WRONG_BUTTON
          //       Output if an invalid button label is passed as an argument.
          //    StatusPanel::MESSAGECODE_CHUTE_FULL
          //       Output if the delivery chute already contains a product.
          //---------------------------------------------------------------------------------------------------------------
          void pressSelectButton(string buttonLabel);
    
          //---------------------------------------------------------------------------------------------------------------
          // SUMMARY
          //    Retrieve the product currently sitting in the delivery chute.
          //
          // RESOURCES
          //    The vending machine relinquishes ownership of the product in the delivery chute.
          //
          // PARAMETERS
          //    None
          //
          // RETURNS
          //    The product currently in the delivery or 0 if no product is currently in the delivery chute.
          //---------------------------------------------------------------------------------------------------------------
          Product *retrieveProduct();
    
          //---------------------------------------------------------------------------------------------------------------
          // SUMMARY
          //    Add the product to the vending machine.
          //
          // RESOURCES
          //    The vending machine takes ownership of the product if and only if the product is accepted.
          //
          // PARAMETERS
          //    pProduct
          //       The product to be added to the vending machine.
          //
          // RETURNS
          //    Whether the product was successfully added to the vending machine.
          //
          // OUTPUTS
          //    StatusPanel::MESSAGECODE_RACK_IS_FULL
          //       Output if the rack to which the product would be added is full.
          //    StatusPanel::MESSAGECODE_NO_RACK_FOR_PRODUCT
          //       Output if name of product being added does not match any of the products allowed to be stored
          //       in the vending machine.
          //---------------------------------------------------------------------------------------------------------------
          bool addProduct(Product* pProduct);
    
          //---------------------------------------------------------------------------------------------------------------
          // SUMMARY
          //    Return the number of products with the given name currently in the vending machine.
          //
          // RESOURCES
          //    None
          //
          // PARAMETERS
          //    productName
          //       The name of the product for which to return a count.
          //
          // RETURNS
          //    The number of products with the given name currently in the vending machine.
          //---------------------------------------------------------------------------------------------------------------
          unsigned getProductCount(string productName) const;
    
          //---------------------------------------------------------------------------------------------------------------
          // SUMMARY
          //    Return the sum of the values of all coins currently in the vending machine.
          //
          // RESOURCES
          //    None
          //
          // PARAMETERS
          //    None
          //
          // RETURNS
          //    The sum of the values of all coins currently in the vending machine.
          //---------------------------------------------------------------------------------------------------------------
          unsigned countTill() const;
    
          //---------------------------------------------------------------------------------------------------------------
          // SUMMARY
          //    Return all coins currently in the vending machine.
          //
          // RESOURCES
          //    The vending machine releases ownership of all coins.
          //
          // PARAMETERS
          //    None
          //
          // RETURNS
          //    All coins currently in the vending machine.
          //---------------------------------------------------------------------------------------------------------------
          vector<Coin *> emptyCoinBox();
    
       private:
          // All coins currently in the vending machine.
          vector<Coin*> coins;
    
          // Buttons visible on the front of the vending machine that customers may push to purchase a product.
          vector<ProductButton *> productButtons;
    
          // Racks of products within the vending machine.  Each rack is associated with a button; when the button
          // is pressed the rack will release the next available product.
          vector<ProductRack *> productRacks;
    
          // Delivery chute at the bottom front of the vending machine; when a product is purchased it is
          // dropped into this delivery chute; the customer can then retrieve the product with her hand.
          DeliveryChute deliveryChute;
    
          // A small display panel visible on the front of the vending machine.  As customers and service professionals
          // use the vending machine appropriate messages are displayed on this panel.
          StatusPanel statusPanel;
    
          // Total monetary balance (in cents) remaining from coins that have been inserted into the vending
          // machine but not been spent on purchasing products.
          unsigned unspentMoneyCents;
       }; 
    }
    
    #endif

  2. #2
    Registered User
    Join Date
    Mar 2009
    Posts
    399

  3. #3
    Registered User
    Join Date
    Aug 2009
    Posts
    34
    Quote Originally Posted by Memloop View Post
    I'm running windows. It looks like Valgrind is for a linux box. Also, I'm a student and don't want to buy anything.

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    For allocation of classes, put print statements in your constructors and destructors. For instance, constructor of class A print "A constructed" and destructor prints "A destructed". If the number of "A constructed" matches the number of "A destructed" then there can be no leaks.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  5. #5
    Registered User
    Join Date
    Mar 2009
    Posts
    399
    You can overload new/new[] and delete/delete[] and add a static counter that you increase every time you allocate new memory, and decrease it when you free it. If the counter is not 0 when you exit your program, you have a memory leak.

  6. #6
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    If you have MSVS there is are debug flags for picking up memory leaks. This may require the pro version. Call this function at the beginning of main.

    Code:
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    It also seems to require these includes:
    Code:
    #if _DEBUG
     #define _CRTDBG_MAP_ALLOC
     #include <stdlib.h>
     #include <crtdbg.h>
    #endif
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  7. #7
    Registered User
    Join Date
    Aug 2009
    Posts
    34
    Quote Originally Posted by King Mir View Post
    If you have MSVS there is are debug flags for picking up memory leaks. This may require the pro version. Call this function at the beginning of main.

    Code:
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    It also seems to require these includes:
    Code:
    #if _DEBUG
     #define _CRTDBG_MAP_ALLOC
     #include <stdlib.h>
     #include <crtdbg.h>
    #endif
    I've tried this, but the memory leak report does not show up in the output box. I am not sure what is preventing it.

  8. #8
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Well, I bothered to actually read the code, and I do see a few problems.

    The management of the coins vector seems odd. In your destructor, you delete the contents of this vector, leading me to believe that you claim ownership of it. But if that's the case, you may have a memory leak here:

    Code:
    bool
    Project1::VendingMachine::insertCoin(Coin *pCoin)                    
    {
       if(pCoin->getValueCents() != 0)
       {
          unspentMoneyCents += pCoin->getValueCents();                   //updates unspentmoney
          // here, you take ownership of the pCoin, and it will be deleted by the destructor
          coins.push_back(pCoin);                                        //adds coin to vector should be used in later function?
          return true;
       }
       else
       {
          // but here, you do not take ownership of it -- who deletes it? Does the caller check, and delete if needed?
          statusPanel.displayMessage(StatusPanel::MESSAGECODE_BAD_COIN);
          return false;
       }
    }
    Passing coins around as dynamically allocated objects seems like overkill. These things are fairly simple, right? The risks introduced by dynamic allocation seem to far outweight any potential reward of doing so. I'd treat the coins as by-value everywhere.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  9. #9
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Quote Originally Posted by steals10304 View Post
    I've tried this, but the memory leak report does not show up in the output box. I am not sure what is preventing it.
    It only outputs when it detects a leek.

    For more information look in msdn.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    steals10304, there was a discussion here about what to do when you want to use Valgrind but are using Windows. What you can learn from this is that it may be feasible to use Valgrind, be it by switching to Linux, by dual booting, using virtualisation, etc. If you would like to read and/or contribute to that discussion, please refer to How Far Should You Go To Use Valgrind?
    Last edited by laserlight; 02-23-2010 at 01:39 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11

    Join Date
    May 2005
    Posts
    1,042
    You may want to find (or develop your own) smart memory management system. As you already have (or soon will) see, you can still shoot yourself in the foot using the standard template library (and reuse the bullet).

    These keywords may assist you to start your search for such a thing:
    - Resource handler
    - Smart handles
    - Boost (library)
    I'm not immature, I'm refined in the opposite direction.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. memory leak
    By rahulsk1947 in forum C Programming
    Replies: 2
    Last Post: 11-11-2007, 01:27 PM
  2. Any Memory Leak Checking Tool?
    By George2 in forum C Programming
    Replies: 4
    Last Post: 06-21-2006, 11:02 PM
  3. Project details: Dedicated
    By Stack Overflow in forum Projects and Job Recruitment
    Replies: 9
    Last Post: 02-22-2005, 03:10 PM
  4. Is it necessary to write a specific memory manager ?
    By Morglum in forum Game Programming
    Replies: 18
    Last Post: 07-01-2002, 01:41 PM

Tags for this Thread