【发布时间】:2014-02-18 22:32:50
【问题描述】:
警告:我知道如果有人现在可能想停止阅读,这篇文章包含 6 个文件的约 275 行代码(虽然没什么复杂的)!我意识到这通常是一件坏事,但这是最后的努力,因为我已经把 cout 放在了所有方法中,显示它们没有崩溃或做任何我没想到的事情,研究了我正在研究的标准方法的实现使用并使用大量输入运行此代码,但有时它会成功运行,有时会失败(完成所有操作后)。我找不到任何模式或损坏的代码段。
该程序模拟了一种具有单个服务器的商店,允许客户订购两种东西中的一种,并且有一条等候线。用户输入模拟长度、每单位时间(分钟)的顾客到达概率,以及制作每件商品所需的时间。运行后,程序会打印出一些统计数据 - 总等待时间(不包括那些仍在排队的人)、服务的客户总数和平均等待时间。
即使进行了长时间的模拟(100,000 分钟),我也看到了成功和失败的运行(同样,只有在模拟完成后才会失败)。起初我认为使用 (>= 1) 来表示到达概率(客户每分钟到达)总是有效的,但后来注意到那些失败了。如果有的话,似乎相当高的到达概率 (> ~.8) 和非常低的 (
当它确实崩溃时,调试器会显示程序计数器在 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 复制构造函数/重载 =/destructor 永远不会被调用,直到最后析构函数执行一次。我也知道我不需要将 customerType (currentCustomer) 作为 serverType 的私有成员之一,但只是为了现实。
【问题讨论】:
-
请做一个简短的独立示例。这样做,您很可能会发现问题所在。 sscce.org
-
哇。 1)如何给我们你用来重现问题的数据而不是 cin 语句。 2) 您对 QueueType 类的单元测试做得如何?在这样的程序中使用它需要它实际上是防弹的。
-
1) 我尝试过 10 -> 100,000 次(通常每个数量级 1 次),到达概率从 0 到 1(0, 0.01, 0.02, 0.1, 0.2, 0.5, 0.75, 0.8 , 0.9, 0.99, 1) 和从 1, 1 到 4, 4 所有情况下的摇晃/圆锥时间 2) 我主要在更改任何变量的方法中使用 cout,向我展示它们正在以我想的方式改变,想要一个循环数组
-
@Cogwheel - 除了使用非常小的输入之外,不确定如何制作一个使用每个类的更短示例? (我试过很多次了)
标签: c++ templates pointers dynamic-arrays