警告:据我所知,如果有人想立即停止阅读,这篇文章包含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的私有成员之一,而只是为了现实。
答案 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中的变化,在重新定位中我根本不需要向后移动,因为它只是在有人离开前面后调用,而在我的添加我的意思是后退一个但是使用 - 而不是+并向前移动...程序已修复。感谢您的回答/评论