2017-08-02 169 views
1

一個非常簡單的代碼,帶有一個奇怪的問題。代碼通過罰款,但我似乎無法得到所需的輸出。我的getStock()getQuantity()功能似乎不起作用。當我調試代碼時,它會顯示'錯誤,讀取內存'。當執行到達s.dispP()代碼意外崩潰。似乎無法找到解決方案。請幫助。謝謝。C++中的內存管理問題

#include<iostream> 
    #include<conio.h> 
    using namespace std; 
    class Sale 
    { 
     class SaleItem 
     { 
      int stock, quantity; 
     public: 

      SaleItem(int pstock, int pquantity) : stock(pstock), quantity(pquantity) 
      { 

      } 
      int getStock() 
      { 
       return stock; 
      } 
      int getQuantity() 
      { 
       return quantity; 
      } 
     }; 

     int sstock, squantity; 
    public: 
     SaleItem *si; 
     void addP() 
     { 
      cout << "Enter Stock: "; 
      cin >> sstock; 
      cout << "Enter Quantity: "; 
      cin >> squantity; 
      SaleItem *si = new SaleItem(sstock, squantity); 
     } 

     void dispP() 
     { 

      cout << si->getStock() << endl << si->getQuantity(); 
     } 
    }; 

    void main() 
    { 
     Sale s; 
     s.addP(); 
     s.dispP(); 
     _getch(); 
    } 

回答

6

錯誤來自於以下幾個方法:

void addP() { 

     cout << "Enter Stock: "; 
     cin >> sstock; 
     cout << "Enter Quantity: "; 
     cin >> squantity; 
     SaleItem *si = new SaleItem(sstock, squantity); 
} 

這裏si僅僅是一個局部變量,而不是你在想它是成員變量。要解決這個問題,只需將si加上this->即可,或者在沒有this指針的情況下使用它。

void addP() { 

     cout << "Enter Stock: "; 
     cin >> sstock; 
     cout << "Enter Quantity: "; 
     cin >> squantity; 
     this->si = new SaleItem(sstock, squantity); 
} 

另一種方法是對成員變量使用命名約定,例如,前綴m__或後綴_


雖然正確的現代C++這裏的做法是不使用原始指針可言。您分配給new的任何內存必須調用delete。而且您還沒有撥打delete來取消分配您分配的內存,並導致內存泄漏。

現代C++解決方案是使用std::unique_ptr來代替自動化內存管理。

public: 
    std::unique_ptr<SaleItem> si; 
    void addP() 
    { 
     cout << "Enter Stock: "; 
     cin >> sstock; 
     cout << "Enter Quantity: "; 
     cin >> squantity; 
     this->si = std::make_unique<SaleItem>(sstock, squantity); 
    } 

    void dispP() 
    { 

     cout << si->getStock() << endl << si->getQuantity(); 
    } 

請注意,您可能根本不需要使用智能指針。簡單的對象可能會。有可用選項的知識在您的處置和使用最好的一個:)

+0

目前尚不清楚,甚至需要一個智能指針。 – juanchopanza

+0

@ juanchopanza是真的,但建議仍然成立:) – Curious

+0

不使用擁有原始指針的建議是。使用'unique_ptr'的建議並非如此。 – juanchopanza

0

你宣佈在addP()方法,它屏蔽了該成員變量的類Salesi局部變量si。因此,成員變量si未初始化,並且隨後引用它會導致崩潰。

+1

它不是'nullptr';它沒有被初始化,所以它得到了那個內存中發生的任何垃圾值。所以,情況更糟;使用'nullptr'至少在大多數平臺上總是會發生崩潰(並且在調試的時候你會清楚地看到它),而對於未初始化的內存,你可以對不相關的數據進行無聲的損壞。 –

+0

@MatteoItalia,謝謝。我編輯了回答 –

+0

downvote刪除。 –

1

這裏

SaleItem *si = new SaleItem(sstock, squantity); 

你是不是分配new表達了si場的結果;相反,您創建了一個本地變量si(即陰影具有相同名稱的字段)並使用new表達式的結果對其進行初始化。

si字段保持未初始化狀態,因此當您稍後嘗試使用它時會發生崩潰(實際上,您很幸運,未初始化的指針可能會默默工作並覆蓋無關的內存)。

要解決這個問題,您必須更改賦值中的新變量定義;因此,該行簡直變成

si = new SaleItem(sstock, squantity); 

請注意,您的班級正在泄漏內存,因爲它調用new沒有相應的delete;這裏的直接解決方法是使用一個智能指針,如unique_ptr,但除非您需要一個指針,否則您應該在Sale之內將SaleItem作爲「常規」(非指針)字段,並且忘記所有內存管理問題。

1

SaleItem *si = new SaleItem(sstock, squantity); 

引入了一個名爲si的局部變量。它不會設置類的成員變量的值。因此,成員變量si保持未初始化狀態。訪問這樣的變量會導致未定義的行爲。

您可以使用

si = new SaleItem(sstock, squantity); 

刪除您所面臨的特殊問題,但要意識到你的類是非常脆弱的。

  1. 成員變量sstocksquantity似乎打算SaleItem,但他們是在該類之外聲明。目前還不清楚這是否是從您的計算機上覆制和粘貼代碼的錯誤,或者您的計算機上也存在錯誤。

  2. 在構造函數中初始化一個類的所有成員變量總是一個好主意。 si可以在類的構造函數中初始化爲nullptr

  3. 你沒有說明你爲什麼需要使用指針。如果你的類需要一個對象,使用一個對象。如果需要對象列表,請使用對象的std::vector

  4. 如果出於某種原因需要在班級中存儲指針,則需要注意The Rule of Three並確保相應地更新班級。

0
SaleItem *si; 
    void addP() 
    { 
     cout << "Enter Stock: "; 
     cin >> sstock; 
     cout << "Enter Quantity: "; 
     cin >> squantity; 
     SaleItem *si = new SaleItem(sstock, squantity); 
    } 

在最後SaleItem *si = new SaleItem(sstock, squantity);您在另外,持有新創建的對象的地址,以及函數的局部SaleItem * SI那麼它將立即超出範圍。

相反,您希望您的成員si被分配給它,所以另一個函數可以使用它。

所以,而不是聲明另一個si,只是指成員si。

SaleItem *si; 
    void addP() 
    { 
     cout << "Enter Stock: "; 
     cin >> sstock; 
     cout << "Enter Quantity: "; 
     cin >> squantity; 
     this->si = new SaleItem(sstock, squantity); 
    } 

附: 如果您正在從一個函數內初始化成員si,並從另一個函數訪問它,則無法確定調用的順序。

要因爲指針SI初始垃圾地址的後頭痛保存自己造成段錯誤,我建議把它初始化爲nullptr :)

0

我不是很清楚爲什麼要使用Si作爲指針到SaleItem? 也許我錯過了一些東西,但它似乎並不是必要的,除非您嘗試創建一個SaleItems列表(然後我認爲您沒有正確實施該類,請參閱下文)。

在任何情況下,與結構我只想去

public: 
      SaleItem si(0,0); 
      void addP() 
      { 
       cout << "Enter Stock: "; 
       cin >> sstock; 
       si.stock=sstock 
       cout << "Enter Quantity: "; 
       cin >> squantity; 
       si.quantity=squantity; 
      } 

      void dispP() 
      { 

      cout << si.getStock() << endl << si.getQuantity(); 
      } 

但是,如果你正在嘗試創建一類銷售也就是那麼你需要以不同的方式做事SaleItems的列表。在那種情況下,你會得到一個指向對象SaleItem的指針。我會理解,si是SaleItem類型的元素的數組。然後,當您創建數組時,您需要爲數組分配內存,這意味着您事先知道該數組將具有的最大數量的元素。然後,您可以擁有一個索引,並且每次向陣列中添加一個新的SaleItem時,都要根據此索引進行操作,注意不要超出分配的最大項目數。

如果您要實現的是一個隨着添加元素而增長的動態數據結構,那麼取決於您選擇實現哪個特定的數據結構,您將需要使用指針。舉個例子,你可以有一個指向下一個SaleItem的指針和一個指向前一個指針的指針。或者,指向下一個SaleItem的指針可以在SaleItem定義中。問題是你必須以某種方式把它們連接到某個地方。如果是這種情況,那麼我建議你閱讀一下數據結構。您可以嘗試

http://www.cprogramming.com/algorithms-and-data-structures.html

https://www.tutorialspoint.com/cplusplus/cpp_data_structures.htm

https://www.tutorialspoint.com/data_structures_algorithms/data_structures_basics.htm

如果這是你所追求的,我希望幫助:)