【问题标题】:C++ strange segmentation faultC++ 奇怪的分段错误
【发布时间】:2012-12-11 05:09:17
【问题描述】:

我的程序出现了一个奇怪的分段错误。 Dlist 是一个创建链接列表的类,该链接列表具有从动态列表中插入和删除项目的操作。我很肯定我的这个类的实现是正确的,但是这段代码正在产生一个段错误。奇怪的是,当我让我的 atleastTwo 和 atleastOne 函数通过引用传递时,段错误消失了,一切都编译了。任何人都可以阐明这个问题吗?

bool atleastTwo(Dlist<double> stack){
try{
    stack.removeFront();
    stack.removeFront();
} catch(emptyList e){
    cout << "Not enough operands\n";
    return false;
}
return true;
}

bool atleastOne(Dlist<double> stack){
try{
    stack.removeFront();
} catch(emptyList e){
    cout << "Not enough operands\n";
    return false;
}
return true;
}

void processInput(inputs usrInput, Dlist<double> &stack){
switch(usrInput){
    case i_add:
        if(atleastTwo(stack)){doOperation(stack, add);}
        break;
    case i_subtract:
        if(atleastTwo(stack)){doOperation(stack, subtract);}
        break;
    case i_multiply:
        if(atleastTwo(stack)){doOperation(stack, multiply);}
        break;
    case i_divide:
        if(atleastTwo(stack)){doOperation(stack, divide);}
        break;
    case i_negation:
        if(atleastOne(stack))negation(stack);
        break;
    case i_duplicate:
        if(atleastOne(stack)){duplicate(stack);}
        break;
    case i_reverse:
        if(atleastTwo(stack)){reverse(stack);}
        break;
    case i_print:
        if(atleastOne(stack)){print(stack);}
        break;
    case i_clear:
        clear(stack);
        break;
    case i_printAll:
        printAll(stack);
        break;
    default:
        break;
}
}

T *removeFront();
// MODIFIES this
// EFFECTS removes and returns first object from non-empty list
//         throws an instance of emptyList if empty

谢谢

【问题讨论】:

  • 你遵守三/五/什么的规则吗? stackoverflow.com/questions/4172722/what-is-the-rule-of-three
  • 是的,有复制构造函数吗?
  • 根据您的描述,问题在于复制 Dlist。我们需要查看 Dlist 的实现以查明问题(我怀疑它与指针复制有关)。
  • 是的,我遵循了3的规则。事实上,当我运行this code here时,编译没有问题。 (Dlist 的相同实现)。不同之处在于这只是我的 atleastTwo 函数的隔离。文件中没有其他函数。
  • 你不能只使用一个堆栈实现来报告它的大小吗?复制,然后尝试/捕捉来确定大小是荒谬的。

标签: c++ linked-list segmentation-fault


【解决方案1】:

关于问题本身,我看不出您的代码如何发生段错误。我怀疑问题出在 Dlist 的代码中,可能是一个糟糕的析构函数?

要解决您的问题,您可以在 Dlist 中实现元素计数并检查它。但也许你不允许修改 Dlist。避免跳跃代码和过多测试的首选解决方案是遵循建议。无需测试操作数的数量,只需尝试一下,并将异常处理程序放入您的处理方法中。第二种解决方案的问题是堆栈可能保持不一致的状态:这意味着您无法继续进行计算,应该从头开始。

void processInput(inputs usrInput, Dlist<double> &stack)
{
  try{
    // .... your old code WITHOUT ifs
  } catch(emptyList e){
    cout << "Not enough operands\n";
  }
}

我想后者是一种可行的方法,您可以保留堆栈的副本并在一个副本上进行计算。这种方式的性能会好得多,而且代码更容易阅读和理解。

希望对你有帮助。

【讨论】:

  • 谢谢。这是一种更好的方法。
【解决方案2】:

如果您按值传递(不使用引用),那么您每次都有效地制作副本。究竟这如何令人困惑尚不清楚,您需要准确研究各种复制构造函数在做什么。但肯定是通过引用传递是你的意思吗?为什么要复制整个集合?

【讨论】:

  • 我遇到的问题是 atleastTwo/One 的这种实现无论如何都不需要更改列表(但同时检查其中是否有两个元素)。我似乎无法找到通过引用传递并解决此问题的方法。
【解决方案3】:

盯着你的Dlist实现代码看了半天(乍一看没有错),我觉得问题出在这里:

template <typename T>
Dlist<T>::Dlist(const Dlist &l){
    removeAll();
    copyAll(l);
}

考虑到在那里执行的操作,在将first(和last)初始化为NULL之前调用removeAll()会导致不好的事情。

Dlist 设计的另一个问题是您持有原始指针(这很棘手,但不一定是坏事,假设每个人都清楚用户有责任删除它们),但您已经实现了深度复制机制。临时 Dlist 对象会泄漏,您传递给 atLeastOneatLeastTwo 函数的副本也会泄漏,除非您手动删除它们的内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多