为什么我的代码中无法访问另一个分支?

时间:2013-12-30 05:31:48

标签: java algorithm design-patterns

为什么以下代码的输出始终为suck。如何获得happy作为输出?为什么happy分支无法访问?

public class HowToMakeStackoverflowBetter {

    private static final int HUMAN_PATIENCE = 10;
    private List<Member> members = new ArrayList<>();
    private int atmosphere = -10;
    private Random r = new Random();
    public HowToMakeStackoverflowBetter(int size) {
        for (int i = 0; i < size; i++) { members.add(new Member()); }
    }
    public Member pick() { return members.get(r.nextInt(members.size())); }

    public class Member {
        private int patience = HUMAN_PATIENCE;
        private Question question = null;
        public Member() { patience = r.nextInt(patience+1) + atmosphere; }
        public void vote(Question q) {
            if (patience >= 0) {
                voteUp(q);
            } else {
                voteDown(q);
            }
        }
        public void ask() {
            question = new Question();
            for (Member member : members) {
                member.vote(question);
            }
        }
        private void voteUp(Question q) { ++q.vote; }
        private void voteDown(Question q) { --q.vote; }
        public String toString() {
            return (question.vote >= 0)? "Happy!" : "Suck!";
        }
    }

    public class Question { private int vote; }

    public static void main(String[] args) {
        HowToMakeStackoverflowBetter stackoverflow = new HowToMakeStackoverflowBetter(100);
        Member me = stackoverflow.pick();
        me.ask();
        System.out.println(me);
    }
}

经过1000次循环后,它给了我们1000次吮吸。我记得2或3年前,事实并非如此。改变了一些事情。

5 个答案:

答案 0 :(得分:2)

两个问题。第一:

linkedList::linkedList(){  
    *sentinel.last=sentinel;  
    *sentinel.next=sentinel;  
    sentinel.str="I am sentinel!!";  
}; 

sentinel是您的成员变量,.last是指向另一个节点的指针。这尚未初始化,因此尝试使用它是未定义的行为。在实践中,它有效地指向内存中(或外部)的随机地址,并且您尝试取消引用指针,然后将整个Sentinel对象复制到想象的指向地址的节点上:即您尝试复制3个指针在sentinel节点成员变量中到内存中的随机地址。

你可能想这样做:

linkedList::linkedList()
{  
    sentinel.last = &sentinel;  
    sentinel.next = &sentinel;  
    sentinel.str = "I am sentinel!!";  
}

其次,您显式调用了LinkedList的析构函数,当执行编译器排列的销毁时,当对象离开它所创建的堆栈作用域时(即main()的末尾),会导致未定义的行为。


我建议您将node.str更改为std::string,就像您希望能够处理变量文本的任何实际程序一样,而不只是指向(常量)字符串文字。如果你混合使用字符串文字和免费存储分配的字符数组,你将无法知道何时调用delete[]来释放内存。您可以通过始终使用new[]创建要存储的字符串数据的新副本来解决此问题,但使用std::string更安全,更容易。

答案 1 :(得分:1)

您忘记初始化sentinel

在下面的代码中,您尝试使用sentinel(同样的事情)初始化sentinel(尚未构建)。因此,您必须将一些内容传递给构造函数,该构造函数可用于初始化您的成员变量sentinel

*sentinel.last=sentinel;

也不需要像这样调用析构函数。一旦myList超出范围,就会调用析构函数。

myList.~linkedList();  

答案 2 :(得分:1)

由于您将其分配为本地变量,因此退出main时将自动销毁mylist。由于您已经显式调用了它的析构函数,这会导致未定义的行为(尝试两次销毁同一个对象)。

作为一个快速指南,显式调用析构函数的时间与placement new结合使用。如果你还不知道那是什么,那很好;只是把它作为你不应该调用析构函数的标志。

答案 3 :(得分:0)

程序可能会崩溃,但是:

    *sentinel.last=sentinel;  
    *sentinel.next=sentinel;  

sentinel未初始化,我在堆栈上有随机值。

答案 4 :(得分:0)

当您尚未初始化成员变量last时,您尝试取消引用指针nextsentinel。 这些去引用*sentinel.last=sentinel *sentinel.next=sentinel导致崩溃,因为没有为指针赋值,你正在改变指针指向的值。

你可以这样做

sentinel.last=&sentinel;  
sentinel.next=&sentinel;

正如其他明确的析构函数调用所指出的那样,这里不需要。