链表的深层副本

时间:2014-05-25 00:26:48

标签: c++ deep-copy doubly-linked-list

我有双向链表,m_Terminal1是列表的开头,m_Terminal2是列表的结尾。这是我的代码

CBusLine(const CBusLine & orig){
      m_Terminal1 = new TStop(orig.m_Terminal1 -> m_Name);
      m_Terminal2 = new TStop(orig.m_Terminal1 -> m_Name);
      TStop * tmpx = m_Terminal2;
      TStop * copy = orig.m_Terminal1;
      copy = copy ->m_Next;
      while(copy != NULL){
          TStop * copy_tmp = new TStop(copy->m_Name);
          tmpx -> m_Next = copy_tmp;
          copy_tmp -> m_Prev = tmpx;
          tmpx = copy_tmp;
          copy = copy->m_Next;
      }

不幸的是,它不起作用,当我想打印出列表时,只有第一项。 这是源文件http://pastebin.com/YCKyZ31K。有人能帮助我吗?提前谢谢

2 个答案:

答案 0 :(得分:0)

您正在创建两个与第一站(m_Terminal1m_Terminal2)同名的对象,并将停靠列表添加到m_Terminal2。因为变量指向内存中的不同位置(由new调用提供),它们不是同一个项目,最后m_Terminal2将具有完整列表,而m_Terminal1只会有第一站。在此过程中,您不会将最后一站存储在m_Terminal2

解决此问题的一种方法是仅初始化并存储第一个停靠点,通过并添加所有停靠点,然后存储(不重新初始化)最后一个停靠点。

CBusLine(CBusLine & orig){
      m_Terminal1 = new TStop(orig.m_Terminal1 -> m_Name);
      TStop * tmpx = m_Terminal1;
      TStop * copy = orig.m_Terminal1;
      copy = copy ->m_Next;
      while(copy != NULL){
          TStop * copy_tmp = new TStop(copy->m_Name);
          tmpx -> m_Next = copy_tmp;
          copy_tmp -> m_Prev = tmpx;
          tmpx = copy_tmp;
          copy = copy->m_Next;
      m_Terminal2 = tmpx;
}

答案 1 :(得分:0)

您应该重用已编写的代码。你写了一个Add()函数,为什么不用呢?

首先,修复Add()函数,使其调用另一个函数,其唯一目的是在序列的末尾添加一个节点:

void CBusLine::Add(istream& is)
{   
    string line;
    while(is.good())
    {
        getline(is, line);
        if(line == "")
            continue;
        AddInternal(line); 
    }
}

void CBusLine::AddInternal(string& line)
{
    TStop * n = new TStop(line);
    if(m_Terminal2 == NULL){
        m_Terminal1 = n;
        m_Terminal2 = n;
    }
    else{
        m_Terminal2 -> m_Next = n;
        n -> m_Prev = m_Terminal2;
        m_Terminal2 = n;
    }
}

分解Add()函数的原因是,现在,复制构造函数(和赋值运算符)变得非常简单。

CBusLine(const CBusLine & orig)
{
    TStop *startTerm = orig.m_Terminal1;
    while ( startTerm != orig.m_Terminal2 )
    {
       AddInternal( startTerm->m_name);
       startTerm = startTerm->m_Next;
    }
}

当然,AddInternal必须正常工作。我假设m_Terminal1和m_Terminal2是链表的开头和结尾。

鉴于AddInternal()正常工作,复制构造函数是一个简单的循环,从开始到结束终端,并使用终端的字符串数据调用AddInternal()。这比在重新创建已在Add()函数中编写的代码更简单,逻辑上更有意义。

请注意,除了复制构造函数之外,还必须编写赋值运算符。