在C ++完成结束时看似随机的程序失败

时间:2014-02-18 22:32:51

标签: c++ templates pointers dynamic-arrays

警告:据我所知,如果有人想立即停止阅读,这篇文章包含6个文件的〜275行代码(虽然没有什么非常复杂的)!我意识到这通常是一件坏事,但这是最后的努力,因为我把cout放在所有方法中,显示它们都没有崩溃或做任何我不会想到的事情,研究标准方法的实现我是使用,并使用各种输入运行此代码,但有时它会成功运行,有时它会失败(完成所有操作后)。我找不到任何模式或破坏的代码段。

该程序使用单个服务器模拟一种商店,允许客户订购两件商品中的一件,并且有一条等候线。用户输入模拟长度,每个时间单位(分钟)的客户到达概率以及每个项目所需的时间。运行后,程序会打印出一些统计数据 - 总等待时间(不包括剩余的等待时间),服务的总客户数和平均等待时间。

即使进行了长时间的模拟(100,000分钟),我也看到了成功和失败的运行(再次,仅在模拟完成后失败)。起初我认为使用(> = 1)到达概率(客户每分钟到达)总是有效,但后来注意到那些失败了。如果有的话,似乎相当高的到达(>〜.8)和非常低的(< =〜.01)到达概率在长时间模拟中最少经常崩溃,但有时仍然可以在短时间内崩溃。很奇怪!

每当 崩溃时,调试器就会显示程序计数器停在queueType的析构函数的结束括号中,但是这个析构函数似乎对我来说非常标准,并且相同的语法适用于其他分配的类堆上的内存与它们的构造函数?我觉得答案必须是一个相当基本的东西,而不是我。

任何帮助将不胜感激,代码如下:

queueType.h:

#ifndef QUEUETYPE_H
#define QUEUETYPE_H
#include <algorithm>
#include <cstdlib>

template<class Type>
class QueueType {
public:
    QueueType();
    ~QueueType();
    QueueType(const QueueType& other);
    Type& getFront() {return queueArray[front];}
    int getNumElements() const {return numElements;}
    void reposition();
    void addElement(Type);
    bool isEmpty() const {return numElements == 0;}
    bool isFull() const {return SIZE == numElements;}
    void updateWaitTimes(Type*&, int&, int&);

    QueueType<Type>& operator=(const QueueType other);

    friend void swap(QueueType& first, QueueType& second) {
        using std::swap;
        swap(first.front, second.front);
        swap(first.back, second.back);
        swap(first.numElements, second.numElements);
        swap(first.queueArray, second.queueArray);
    }
private:
    static const int SIZE = 25;
    int front, back, numElements;
    Type *queueArray;
};

template<class Type>
QueueType<Type>::QueueType() {
    queueArray = new Type[SIZE];
    front = back = numElements = 0;
}

template<class Type>
QueueType<Type>::~QueueType() {
    delete [] queueArray;
}

template<class Type>
QueueType<Type>::QueueType(const QueueType& other):
        queueArray(new Type[SIZE]),
        front(other.front),
        back(other.back),
        numElements(other.numElements)
{
    std::copy(other.queueArray, other.queueArray + SIZE, queueArray);
}

template<class Type>
void QueueType<Type>::reposition() {
    front = (front + 1) % SIZE;
    back = (back + 1) % SIZE;
    numElements--;
}

template<class Type>
void QueueType<Type>::addElement(Type newElement) {
    if (isEmpty()) {
        queueArray[0] = newElement;
        front = back = 0;
        numElements = 1;
    } else {
        back = (back - 1) % SIZE;
        queueArray[back] = newElement;
        numElements++;
    }
}

template<class Type>
void QueueType<Type>::updateWaitTimes(Type*& element, int& position, int& counter) {
    if (isEmpty()) {
        element = NULL;
    } else {
        if (position == 0) {
            position = front;
        }
        element = &queueArray[position];
        position = (position + 1) % SIZE;
    }
    if (counter == numElements) {
        element = NULL;
    }
    counter++;
}

template<class Type>
QueueType<Type>& QueueType<Type>::operator=(const QueueType other) {
    swap(*this, other);
    return *this;
}
#endif  /* QUEUETYPE_H */

customerType.h:

#ifndef CUSTOMERTYPE_H
#define CUSTOMERTYPE_H

class CustomerType {
public:
    CustomerType();
    CustomerType(int, int);
    ~CustomerType();
    CustomerType(const CustomerType& other);
    void incrementWaitTime() {waitTime++;}
    int getArrivalTime() const {return arrivalTime;}
    int getWaitTime() const {return waitTime;}

    CustomerType& operator=(const CustomerType& other);
private:
    int ID, arrivalTime, waitTime;
};

#endif  /* CUSTOMERTYPE_H */

customerType.cpp:

#include "customerType.h"

CustomerType::CustomerType() {
    waitTime = arrivalTime = ID = 0;
}

CustomerType::CustomerType(int arrivalTime, int ID) {
    this->arrivalTime = arrivalTime;
    this->ID = ID;
    waitTime = 0;
}

CustomerType::~CustomerType() {
}

CustomerType::CustomerType(const CustomerType& other) {
    waitTime = other.waitTime;
    arrivalTime = other.arrivalTime;
    ID = other.ID;
}

CustomerType& CustomerType::operator=(const CustomerType& other) {
    waitTime = other.waitTime;
    arrivalTime = other.arrivalTime;
    ID = other.ID;
    return *this;
}

serverType.h:

#ifndef SERVERTYPE_H
#define SERVERTYPE_H

#include "customerType.h"
#include <cstdlib>
#include <string>

class serverType {
public:
    serverType();
    ~serverType();
    serverType(const serverType& other);
    bool isFree() const {return (status == "free");}
    void setCustomer(CustomerType& newCustomer, int& transactionTime);
    void decrementTransactionTime();

    serverType& operator=(const serverType& other);
private:
    std::string status;
    int transactionTime;
    CustomerType currentCustomer;
};

#endif  /* SERVERTYPE_H */

serverType.cpp:

#include "serverType.h"

serverType::serverType() {
    status = "free";
    transactionTime = 0;
}

serverType::~serverType() {
}

serverType::serverType(const serverType& other) {
    status = other.status;
    transactionTime = other.transactionTime;
    currentCustomer = other.currentCustomer;

}

void serverType::setCustomer(CustomerType& newCustomer, int& transactionTime) {
    currentCustomer = newCustomer;
    this->transactionTime = transactionTime;
    status = "busy";
}

void serverType::decrementTransactionTime() {
    transactionTime--;
    if (transactionTime == 0)
        status = "free";
}

serverType& serverType::operator=(const serverType& other) {
    status = other.status;
    transactionTime = other.transactionTime;
    currentCustomer = other.currentCustomer;
    return *this;
}

main.cpp中:

#include "queueType.h"
#include "serverType.h"
#include <ctime>
#include <climits>
#include <iostream>
using namespace std;

int main(int argc, char** argv) {

    int simulationTime, coneTime, shakeTime, currentTime = 0;
    int customerID = 1, totalWaitTime = 0, customersServiced = 0;
    double arrivalProb;

    cout << "Time-driven ice cream shop simulation" << endl
            << "Enter the following information to begin:" << endl << endl;
    cout << "Length of simulation (in minutes): ";
    cin >> simulationTime;
    cout << endl << "Probability of customer arrival each minute (example: 0.25): ";
    cin >> arrivalProb;
    cout << endl << "Minutes to make an ice cream cone: ";
    cin >> coneTime;
    cout << endl << "Minutes to make a shake: ";
    cin >> shakeTime;
    cout << endl << endl;

    QueueType<CustomerType> Line;
    serverType server;
    float chance;
    srand(time(0) % INT_MAX);

    while (currentTime < simulationTime) {
        chance = float (rand())/RAND_MAX;
        if (chance < arrivalProb) {
            if (!Line.isFull()) {
                Line.addElement(CustomerType(currentTime, customerID));
                customerID++;
            } else {
                cout << "Customer #" << customerID 
                        << " came during a full line and left!" << endl;
                customerID++;
            }
        }
        if (server.isFree() && (!Line.isEmpty())) { //going with 40% shake, 60% cone
            customersServiced++;
            if (chance < 0.4) {
                server.setCustomer(Line.getFront(), shakeTime);
            } else {
                server.setCustomer(Line.getFront(), coneTime);
            }
            totalWaitTime += Line.getFront().getWaitTime();
            Line.reposition();
        } else if (!server.isFree()) {
            server.decrementTransactionTime();
            CustomerType *customerPointer = new CustomerType();
            int position = 0, counter = 0;
            Line.updateWaitTimes(customerPointer, position, counter);
            while (customerPointer != NULL) {
                (*customerPointer).incrementWaitTime();
                Line.updateWaitTimes(customerPointer, position, counter);
            }
            delete customerPointer;
        }
        currentTime++;
    }
    cout << endl << endl << "Simulation complete." << endl << endl;
    cout << "Total wait time: " << totalWaitTime << endl
            << "Customers serviced: " << customersServiced << endl
            << "Average wait time: " << float (totalWaitTime) / customersServiced;
    return 0;
}

请注意,在析构函数最后执行一次之前,queueType复制构造函数/ overloaded = /析构函数永远不会被调用。我也知道我不需要将customerType(currentCustomer)作为serverType的私有成员之一,而只是为了现实。

3 个答案:

答案 0 :(得分:2)

你在这里管理不善:

CustomerType *customerPointer = new CustomerType();
int position = 0, counter = 0;
Line.updateWaitTimes(customerPointer, position, counter);

您正在为customerPointer分配内存。然后在Line.updateWaitTimes函数中更改customerPointer指向的值。然后你这样做:

delete customerPointer;

因此,您分配的内容和删除的内容具有不同的值。您试图删除未在动态分配的块的开头处启动的地址,从而破坏堆。

如果你要删除的是指向动态分配内存的指针,即你是用这种方式设计的,但是它是一个“开头”原始的“不同”指针,那么你需要重写你的代码所以你不是在customerPointer和Line.updateWaitTimes函数之间做这个“指针舞”。

这只是您需要修复的代码的许多问题之一。一个解决方法是在main()函数中退出手动内存管理。学习编写最小化或消除原始裸指针使用的代码。是的,您的QueueType类必须执行内存管理,但这并不意味着您的main()也必须这样做。

此外,您的QueueType类维护自己的内存,不应被外部实体欺骗。查看你的QueueType :: updateWaitTimes函数 - 为什么它给出了传入的“element”指针的指针?然后在main()中使用此指针指向内部队列和finagle,这会产生灾难性的结果。编写这样的代码意味着你还没有完全理解“封装”的含义。

答案 1 :(得分:1)

这一行很可能是问题,因为它可以留下负面的

back = (back - 1) % SIZE;

你可能意味着像

back = (SIZE + back - 1) % SIZE;

答案 2 :(得分:0)

WOW。刚才终于意识到它崩溃的原因是我在queueType :: reposition和queueType :: addElement中的变化,在重新定位中我根本不需要向后移动,因为它只是在有人离开前面后调用,而在我的添加我的意思是后退一个但是使用 - 而不是+并向前移动...程序已修复。感谢您的回答/评论