【问题标题】:What is wrong with my Copy Constructor?我的复制构造函数有什么问题?
【发布时间】:2012-02-24 23:06:31
【问题描述】:

为什么进入复制构造函数会崩溃?

在您将在我的类定义中找到的复制过程中,我确保将作为其他原始队列的副本创建的队列在开始复制之前为空:假设队列 q1 不为空并且我想把q1变成q2。我想在将q2的内容复制到q1之前清空q1的内容..

#include <iostream>
#include <string>
#include <cassert>

using namespace std;

class Dnode
{
    public:
       Dnode(int);
       int  n;
       Dnode*   l, *r;
};

Dnode::Dnode(int tx)
{
    n = tx;
    l = r = NULL;
}

class Queue // reminder: insertions at the rear, deletions at the front
{
    public:
       Queue();
       void enqueue(int x);
       int dequeue(void);
       bool empty(void) const;
       void display(void) const;
       Queue(const Queue&); //copy constructor

    private:
       Dnode*   front, *back;
       void copy(Dnode*);
       void free();

};

Queue::Queue()
{
    front = back = NULL;
}


void Queue::enqueue(int x)
{
    Dnode*  d = new Dnode(x);
    if (empty())
        front = back = d;
    else
    {
        back->r = d;
        d->l = back;
        back = d;
    }
}

int Queue::dequeue(void)
{
    assert(! empty());
    Dnode*  temp = front;
    front = front->r;
    if (front == NULL)
        back = NULL;
    else    front->l = NULL;
    int x = temp->n;
    delete temp;
    return x;
}


bool Queue::empty(void) const
{
    return front == NULL;
}

void Queue::display(void) const
{
    for (Dnode* d = front; d != NULL; d = d->r)
        cout << d->n << " ";
    cout << endl;
}

void Queue::copy(Dnode* dn) // "dn" will be "Front" of Queue being copied
{                           // this procedure will be called in Copy Constructor  
    Dnode* temp=front;      // found underneath this procedure
    while(front!=back)      
    {                       
        front=front->r;
        delete temp;
        temp=front;
    }

    delete temp;

    front=back=temp=NULL;

    if(dn!=NULL)
    {
        while(dn->r!=NULL)
        {
            enqueue(dn->n);
            dn=dn->r;
        }
        enqueue(dn->n);
    }
}

Queue::Queue(const Queue& x)
{
    copy(x.front);
}

int main()
{
    Queue   q;
    if (q.empty()) cout << "q empty" << endl;

    for (int i = 0; i < 10; i++) q.enqueue(i);

    q.display();

    int x = q.dequeue();

    cout << "x is " << x << endl;

    q.display();

    Queue q1(q); //<----program crashes when we get here

    q1.display();
}

【问题讨论】:

  • 复制时为什么要删除?复制期间无需释放内存。实际上,您应该在 Queue 的新实例中分配内存来保存副本。
  • 你到处使用和删除未初始化的指针...
  • 如您所说,清空将成为其他队列副本的队列可能是不必要的,但这不应该是程序崩溃的原因吗?我做错了什么?

标签: c++ class constructor copy


【解决方案1】:

您将复制构造函数与赋值运算符混淆了。在赋值运算符中,您必须删除当前队列并将其替换为第二个参数的副本。但这是一个复制构造函数。当前没有队列。您的成员未初始化。因此,当您开始尝试删除现有队列时,您会弄乱未初始化的指针。

【讨论】:

    【解决方案2】:

    您忘记在复制构造函数中初始化 backfront

    void Queue::copy(Dnode* dn) // "dn" will be "Front" of Queue being copied
    {   
      Dnode* temp=front;      // found underneath this procedure
      while(front!=back)      
      {                       
          front=front->r;
          delete temp;
          temp=front;
      }
    

    while 循环随后随机运行,因为 front 被未初始化,并导致崩溃。

    【讨论】:

    • 我假设在调用复制过程时正面和背面都有值,但我不可能知道这些是什么。顺便说一句,我相信你对未初始化的指针没问题,只是当涉及到复制构造函数时我有点困惑......
    • @user1073400 你不能delete 不是newd,这是未定义的行为。但这就是您在复制构造函数中所做的。
    • @user1073400:你的复制成员函数没问题。问题是,当您调用Queue q1(q); 时,您创建的对象q1 具有frontback 的随机值,因为创建它的构造函数没有初始化它们。反过来,front (可能)不为空并且与后面不同。
    • @jrok:崩溃甚至可能发生在delete之前的行:front=front-&gt;r;调用r并将无效指针作为this传递给它。
    • hmm... 如果在 main() 中我键入类似“Queue q1;”的 smth,那不会根据默认构造函数将其指针初始化为 NULL 吗?如果我然后使用“q1(q);”呢? ??
    【解决方案3】:

    你需要将你的前后指针初始化为null,然后循环通过源Queue x抓取每个Dnode并将其排入新队列。

    【讨论】:

    • 如果我的“新”队列毕竟不是空的,我想把它变成队列 x 的副本怎么办?
    • 你不会使用你的复制构造函数。要完成您的要求,您需要先排空队列,然后调用更正的 copy()。
    • @user1073400 你的“新”队列怎么可能包含任何东西?当您的副本 constructor 正在运行时,该对象甚至还没有完全构建,它正在从头开始重新构建。也许您将复制构造函数与赋值运算符混淆了?
    • @jrok 宾果游戏! :) 我相信这就是我一直困惑的地方。我认为复制构造函数构造了一些 Queue Qx 的副本,并且可以使用已经存在的 Queue Qy 将其转换为 Qx 的副本..哇..好对吗? :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-29
    • 1970-01-01
    • 2017-08-12
    • 1970-01-01
    • 1970-01-01
    • 2013-10-16
    相关资源
    最近更新 更多