【问题标题】:Why does c++ program crash after temporary object is destroyed at end of scope为什么在范围结束时临时对象被销毁后c ++程序崩溃
【发布时间】:2015-01-17 06:59:49
【问题描述】:

所以我有点困惑。在调用 changeList() 后尝试 printList() 时,这段代码将失败。但是,当我删除析构函数时,代码运行时不会崩溃。我的问题是,为什么?我知道在我在这里的代码中,我将对象按值传递给changeList,因此,一个临时对象被创建为参数的副本。对此临时对象所做的任何更改都不会影响我传入的原始对象。那么为什么程序会崩溃,就好像我正在访问一个被破坏的对象一样?不应该在 changeList 完成后销毁临时对象,然后 printList 应该只打印 1 到 10 而不是 1 到 45。

void printList(Node*);
void changeList(LinkedList);

int main(){

    LinkedList list;

    for (int i = 0; i < 10; i++)
        list.append(new Node(i+1, nullptr));

    changeList(list);
    printList(list.getHead());
    system("pause");
    return 0;
}

void changeList(LinkedList list){
    list.append(new Node(45, nullptr));
}

void printList(Node* head){
    Node* temp = head;
    if (temp != nullptr){
        cout << temp->value << endl;
        printList(temp->next);
    }//end if
}

【问题讨论】:

  • Changelist 复制列表 - 我想这不是你想要的
  • 调用外部程序“暂停”是没有意义的。使用 Ctrl-F5 从 Visual Studio 运行程序并保持控制台窗口打开。您的代码没有暴露问题,可能是您没有显示的类定义有问题。
  • 你的析构代码在哪里?
  • 这是一个疯狂的猜测。您还没有定义复制构造函数。因此,调用将参数传递给changeList() 的复制构造函数复制了列表头。当该临时节点被销毁时,它会销毁所有节点,因为它们是共享的。您没有意识到这一点,因为节点共享意味着append 具有预期的结果。

标签: c++ pointers temporary-objects


【解决方案1】:

如果我假设正确,LinkedList 的析构函数将破坏列表中的所有节点。我还假设复制构造函数制作了列表的浅表副本。 (如果您没有显式实现复制构造函数,则这是默认值。)当您运行代码时会发生这种情况:

void printList(Node*);
void changeList(LinkedList);

int main(){

    LinkedList list; //first instance is created

    for (int i = 0; i < 10; i++)
        list.append(new Node(i+1, nullptr)); // nodes added to the first instance

    changeList(list); // copy constructor called, second instance is 
                      // created with the same set of node objects


    printList(list.getHead()); // nodes does not exist any more because of
                               // the destructor called at the end of changeList


    system("pause");
    return 0;
}

void changeList(LinkedList list)  // copy constructor called, second instance is created
    list.append(new Node(45, nullptr));  // nodes added to the same chain of nodes
} // destructor is called, all the nodes are destroyed

void printList(Node* head){
    Node* temp = head;
    if (temp != nullptr){
        cout << temp->value << endl;
        printList(temp->next);
    }//end if
}

您可以通过在changeList 函数中接受引用参数来解决此问题:

void changeList(LinkedList &list)  // no copy
    list.append(new Node(45, nullptr));  
} // no destructor is called

【讨论】:

  • 所以 changeList 制作了一个临时节点列表,其指针与我拥有的原始节点相同?那么它不是复制品……不是吗? ChangeList 获取了我的列表,创建了自己的列表对象,然后使用了我在原始列表中使用的相同节点指针?
  • 所以当一个对象通过“值”传递时,它的指针也不会被“复制”吗?我本来希望分配新指针,并将原始指针中的值复制到新指针中。
  • 这取决于您的LinkedList 实现,但如果您确实 nod 明确编程它这样做,那么它不会复制您的节点对象。指针当然会被复制,但是在典型的链表实现的情况下,只复制包含的头指针,它仍然指向同一个节点对象。阅读 this 维基百科关于浅拷贝和深拷贝的文章。
猜你喜欢
  • 2020-04-10
  • 1970-01-01
  • 2022-08-15
  • 2015-12-11
  • 2017-04-18
  • 2019-08-19
  • 1970-01-01
  • 2015-01-10
相关资源
最近更新 更多