【问题标题】:How to Initialize class member that is a pointer to a structure如何初始化作为结构指针的类成员
【发布时间】:2020-07-22 06:53:31
【问题描述】:

我有一个问题,应用程序在函数内部引用 if(!head) 的代码行崩溃:insertNode()。 head 和 tail 是 node* 类型的类成员。看起来,我在类成员的方式上遗漏了一些东西:头、尾的初始化.. 这是运行时错误:“SLinkedlist_array.exe 中 0x00245246 处的未处理异常:0xC0000005:访问冲突读取位置 0x00000000。”

    slinkedlist.h:
    typedef struct node
    {
        int value;
        struct node* next;
    } node;

    class slinkedlist
    {
    public:
        //ctor, dtor, insertNode(int, int), displayList()
    private:
        node* head, tail;
    };

    slinkedlist.cpp:
    bool slinkedlist::insertNode(int value, int aftNodeVal)
    {
        int toinsertval = value;
        int searchkey = aftNodeVal;
        bool retval = false;

        // If it's a new linked list
        if(!head)  // THIS IS WHERE THE APPLICATION CRASHES!
        {
            node* head = new node;
            head->value = toinsertval;
            head->next = NULL;
            return true;
        }
        else //It's not a new list
        {
            while(head->next != NULL)
            {
                 //some more code here... 
            }
        }
        return retval;
    }

    void slinkedlist::displayList()
    {
        while(!head)
        {
            do
            {
                cout << head->value << " " ;
                head = head->next;
            }
            while(head->next != NULL);
        }
        //return void;
    }

    main.cpp:
    int main()
    {
        slinkedlist *s1 = NULL;
        s1->insertNode(4, -1);
        s1->displayList();
        while(1);
    }`

【问题讨论】:

  • s1-&gt;insertNode(4, -1);,但是s1还没有初始化。
  • 无关:typedef struct node { int value; struct node* next; } node;typedefing 不是必需的。 C++ 非常聪明,可以弄清楚没有它的节点是什么。 struct node { int value; struct node* next; }; 就足够了。
  • 相关:阅读Member Initializer List
  • 根据您定义变量的方式和位置,它可能会或可能不会被初始化。 Some reading on those rules。在这种情况下,你是对的,问题是初始化。 headtail 没有被初始化。 Here's a link to documentation on the may different ways you can initialize in C++。选择一个最有意义的。但是……

标签: c++ visual-studio class crash runtime


【解决方案1】:

答案很简单:这里有空指针解引用:

slinkedlist *s1 = NULL;
s1->insertNode(4, -1);
s1->displayList();

这正是系统告诉您的内容:“访问冲突读取位置 0x00000000”

解决方案可以是:

slinkedlist *s1 = new slinkedlist;
s1->insertNode(4, -1);
s1->displayList();
delete s1;

或者像这样(为什么不只使用堆栈上的一个对象?):

slinkedlist s1;
s1.insertNode(4, -1);
s1.displayList();

或更多 C++ 方式(如果您需要指针):

auto s1 = make_unique<slinkedlist>(); // s1 is a std::unique_ptr<slinkedlist>
s1->insertNode(4, -1);
s1->displayList();

【讨论】:

    【解决方案2】:
    slinkedlist *s1 = NULL;
    

    定义了一个指向slinkedlist 的指针并初始化它不幸的是它将它初始化为NULL,一个安全的停放地址(通常)不允许存在任何对象。对于绝大多数 CPU(我曾经使用过的每个 CPU)来说,访问 NULL 周围的这个死区会使程序崩溃,从而更容易检测错误。

    这里不需要指针。如果您不需要指针,请不要使用指针。你的生活会轻松很多。

    int main()
    {
        slinkedlist s1; // default initializes
        s1.insertNode(4, -1);
        s1.displayList();
        while(1); // rethink this. If you want to hold a program open to see the output 
                  // while debugging, place a breakpoint in the debugger.   
    }
    

    Default initializings1 单独对您没有帮助,因为它将做绝对最少的工作来初始化其成员变量,并且在指针的情况下,最少的工作是什么都不做,离开 head 和 @ 987654328@ 未初始化并指向(有点。tail 不是指针)到一个不确定的位置。因为您还没有询问将NULL 分配给tail 应该得到的编译器错误,所以程序显然没有初始化tail,我假设slinkedlist 构造函数没有做太多。

    旁注:如果您有一个不做任何事情(并且不需要做任何事情)的构造函数或析构函数,请将它们排除在外,让编译器生成适当的代码。不存在(也不需要存在)的代码没有错误。

    class slinkedlist
    {
    public:
        //ctor, dtor, insertNode(int, int), displayList()
    private:
        node* head, tail; // the * only applies to head.
    };
    

    可能是

    class slinkedlist
    {
    public:
        //ctor, dtor, insertNode(int, int), displayList()
    private:
        node* head = nullptr;
        node* tail = nullptr;
    };
    

    如果您正在编译最新的(2011 年或更新的)C++ 标准。您不需要构造函数,使用默认分配为您完成工作。您仍然需要一个析构函数以及一个复制构造函数和一个赋值运算符来满足The Rule of Three

    在较旧的 C++ 标准中,您需要使构造函数更智能

    class slinkedlist
    {
    public:
        slinkedlist(): head(NULL), tail(NULL)
        {
        }
        //dtor, insertNode(int, int), displayList()
    private:
        node* head; // I recommend splitting the definitions up. It makes the code easier 
                    // to read and makes it harder to make mistakes.
        node* tail;
    };
    

    您仍然需要一个析构函数、一个复制构造函数和一个赋值运算符。

    请注意,这也适用于node。如果你动态分配一个节点并且没有明确地将next 设置为一个值,你将不知道next 指向哪里,并且所有的测试都像

    while(head->next != NULL)
    

    会严重失败。

    【讨论】:

    • 感谢大家的投入!我已经尝试过,就像你们大多数人指出的那样,这是我必须修复的 NULL 指针实例化,并且程序现在可以正常工作。Tha
    • @Manasa,你有任何更新吗?如果您的案例已经解决,请帮忙标记答案。
    • @Jeaninez - MSFT,确定我已经标记了对我有帮助的答案。
    • @ Jeaninez - MSFT,我希望我已经按照您的建议标记了有用的答案。只是与您核对一下,因为我是在 StackOverflow 上发帖的新手。
    猜你喜欢
    • 1970-01-01
    • 2012-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-13
    • 2020-05-28
    相关资源
    最近更新 更多