c ++中的内存管理问题

时间:2017-08-02 05:53:16

标签: c++ class memory-management

一个非常简单的代码,有一个奇怪的问题。代码很好但我似乎无法获得所需的输出。我的 getStock() getQuantity()功能似乎不起作用。当我调试代码时,它会显示“错误读取内存”。当执行到达 s.dispP()时,代码意外崩溃。似乎无法找到解决方案。请帮助。谢谢。

    #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 个答案:

答案 0 :(得分: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();
    }

请注意,您可能根本不需要使用智能指针。简单的对象可能会。了解您可以使用的选项并使用最好的选项:)

答案 1 :(得分:1)

下面

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

您并非new表达式的结果分配到si字段;相反,您创建了一个本地变量si(隐藏了具有相同名称的字段)并使用new表达式的结果初始化它。

si字段仍然未初始化,因此当您稍后尝试使用它时会发生崩溃(实际上,您很幸运,未初始化的指针可能会无声地显示正常工作并覆盖不相关的内存)。

要解决此问题,您必须更改作业中的新变量定义;所以,那条线就变成了

si = new SaleItem(sstock, squantity);

请注意,您的类正在泄漏内存,因为它调用new而没有相应的delete;这里的立即修复是使用智能指针,如unique_ptr,但是,除非你因某些其他原因需要指针,这里你应该只有SaleItem作为“常规”(非指针) )Sale内的字段,忘记所有内存管理问题。

答案 2 :(得分: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并确保相应地更新您的班级。

答案 3 :(得分:0)

您在si方法中声明了一个局部变量addP(),该方法隐藏了类si的成员变量Sale。因此,成员变量si未初始化,随后对它的引用会导致崩溃。

答案 4 :(得分: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。

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

P.S。 如果要从函数中初始化成员si,并从另一个函数访问它,则无法确定调用的顺序。

为了避免因为指针si中的初始垃圾地址导致段错误而导致以后头痛,我建议将其初始化为nullptr:)

答案 5 :(得分: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();
          }

但是,如果您要创建的是一个类Sale,它是SaleItems的列表,那么您需要以不同的方式处理事物。在这种情况下,是的,你将有一个指向对象SaleItem的指针。我会理解si是SaleItem类型的元素数组。然后,您需要在创建数组时为数组分配内存,这意味着您事先知道此数组将具有的最大元素数。然后你可以得到一个索引,每次你向数组中添加一个新的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

如果这就是你所追求的,我希望这有助于:)