Temple of The Roguelike Forums
Development => Programming => Topic started by: Fenrir on September 17, 2009, 02:39:03 AM
-
I'm using C++ and pdcurses.
Anyone know what could cause a program to crash after it exits? After my program's main() function returns, Windows tells me that "Roguelike.exe has stopped working. Windows is checking for a solution to the problem", which is its usual response when something goes haywire. I don't know why it bothers to look for a solution; it never finds one.
I don't know what the hell I did. Could it be something that was newed and not deleted?
-
If something is crashing as your program exits, the error will often appear after it closes. This will happen especially with errors in destructors of classes. There could also be some system that hasn't been shut down properly. It could also be a library whose exit function hasn't been called. Just a few ideas.
-
Check out that you didn't forget [] in delete when deleting an array.
-
I dont think forgetting to deallocate memory will cause a crash, most modern OS will reclaim this anyway.
I second Elig sugestions. Probably some instance of a class going out of scope and calling the destructor, ( which will happen at the end of main), where something wet wrong.
Debug, debug, debug. Generally a debugger will tell you where its crashing. Maybe move to a modern IDE if you have not done so already. But since you are a windows user I assume you already have one. I use Visual C++ express myself.
-
I dont think forgetting to deallocate memory will cause a crash
I know it will, in case when you forget [] in array delete.
-
Semantics, semantics...
Incorrectly deallocating memory can cause a crash, but not forgetting to deallocate on exit as I said.
-
I'm using Dev C++. I've given up on the debugger. The damn thing is convinced that my project doesn't have debugging information, no matter how many times I enable debugging information and rebuild. When I'm trying to hunt down an error, I paste a bit of code in the suspected place that displays a message and waits for user input before proceeding. If I don't see the message before the crash, I know the problem is happening sooner, if I do see it I know the problem occurs later in the code.
Obviously, a debugger that works would be better. I'll take a look at Visual C++ Express.
Krice, I don't think that's the problem in this case. I'm sure I deleted all my arrays with [].
Ah, while typing this post, I discovered that one of the items that I give the player in main() is causing the crash somehow. I'm thinking that perhaps two destructors may be trying to delete the same item or something. I'll keep poking around and let you know what happens.
EDIT:
I was deleting something that wasn't newed in the first place. Thanks for the help, guys.
-
I'm using Dev C++. I've given up on the debugger.
Obviously, a debugger that works would be better. I'll take a look at Visual C++ Express.
You cannot create a roguelike program without extensive use of a debugger! Not being a Dev C++ user I cant be of much help other than to suggest the obvious and make sure you are not trying to debug a release build.
Visual Studio's debugger is great.
-
You cannot create a roguelike program without extensive use of a debugger!
Let's just say that following good class design and memory management rules really helps to avoid the usual problems with C/C++ and reduce the need for debugger. Back some years Kaduria was basically C without any OOP and it had really difficult problems with memory corruptions. If you don't use preventive methods you are most likely to run in trouble and need a good debugger.. I would anyway suggest Visual C++, because it's far better than DevC++ in so many ways.
-
By Odin's beard, Visual C++ spits 364 errors out at me! "Undeclared identifier" is the most common. I must have set up the project incorrectly, but I can't imagine how.
-
"Undeclared identifier" is the most common.
It's probably pdcurses. You need to set up it correctly, it doesn't work just like that.
-
Set your include paths correctly.
-
I set up pdcurses correctly. I made a little test program that runs just fine. It's my classes that are the problem. Here's a piece of my code (shield your eyes!):
utility.h
// utility.h - for general useful things like random numbers
#ifndef _UTILITY_
#define _UTILITY_
// Forward declare everything I need here. Bad idea?
class Dungeon;
//class Creature;
class Level;
class RNG
{
public:
static int randInRange(int min, int max);
static int roll(std::string dice);
};
class DEBUG
{
public:
static void checkpoint();
};
class StringOp
{
public:
template<class T>
static std::string toString(const T& t)
// not my code!
{
std::ostringstream stream;
stream << t;
return stream.str();
}
template<class T>
static T fromString(const std::string& s)
// not my code
{
std::istringstream stream (s);
T t;
stream >> t;
return t;
}
};
class Color
{
public:
enum Colors
{
BLACK=0,
DARK_BLUE,
DARK_GREEN,
TEAL,
DARK_RED,
PURPLE,
BROWN,
LIGHT_GRAY,
DARK_GRAY,
BLUE,
GREEN,
CYAN,
RED,
PINK,
YELLOW,
WHITE,
SELECTED
};
static void initColorPairs();
static void color(int color);
};
#endif
utility.cpp
// utility.cpp
#include "headers.h"
int RNG::randInRange(int min, int max)
{
if(max < min) max = min;
int number = (rand()%(max-min+1))+min;
}
int RNG::roll(std::string roll)
{
int dQuantity, dSize; // Number and size of dice
int divider; // where the 'd' is in the string
int number = 0; // the random number
divider = roll.find("d");
if(divider == std::string::npos) return 0;
dQuantity = StringOp::fromString<int>(roll.substr(0,divider));
dSize = StringOp::fromString<int>(roll.substr(divider+1));
for(int i=0; i<dQuantity; i++)
{
number += randInRange(1,dSize);
}
return number;
}
void DEBUG::checkpoint()
{
mvaddstr(0,0,"DEBUG CHECKPOINT!");
getch();
}
void Color::initColorPairs()
{
init_pair(0,COLOR_BLACK,COLOR_BLACK);
for(int i=1; i<=15; i++)
{
init_pair(i,i,COLOR_BLACK);
}
init_pair(SELECTED,BLACK,WHITE);
}
void Color::color(int color)
{
attron(COLOR_PAIR(color));
}
headers.h
// headers.h ties all the project files together.
#ifndef _HEADERS_
#define _HEADERS_
#include <stdlib.h>
#include <curses.h>
#include <time.h>
#include <string>
#include <vector>
#include <cmath>
#include <sstream>
#include <iostream>
#include "utility.h"
#include "entity.h"
#include "item.h"
#include "creature.h"
#include "player.h"
#include "ai.h"
#include "dungeon.h"
#include "menu.h"
#endif
errors:
c:\jake\projects\roguelike\utility.cpp(4) : error C2653: 'RNG' : is not a class or namespace name
c:\jake\projects\roguelike\utility.cpp(10) : error C2653: 'RNG' : is not a class or namespace name
c:\jake\projects\roguelike\utility.cpp(20) : error C2653: 'StringOp' : is not a class or namespace name
c:\jake\projects\roguelike\utility.cpp(20) : error C2065: 'fromString' : undeclared identifier
c:\jake\projects\roguelike\utility.cpp(20) : error C2062: type 'int' unexpected
c:\jake\projects\roguelike\utility.cpp(22) : error C2653: 'StringOp' : is not a class or namespace name
c:\jake\projects\roguelike\utility.cpp(22) : error C2065: 'fromString' : undeclared identifier
c:\jake\projects\roguelike\utility.cpp(22) : error C2062: type 'int' unexpected
c:\jake\projects\roguelike\utility.cpp(31) : error C2653: 'DEBUG' : is not a class or namespace name
c:\jake\projects\roguelike\utility.cpp(37) : error C2653: 'Color' : is not a class or namespace name
c:\jake\projects\roguelike\utility.cpp(45) : error C2065: 'SELECTED' : undeclared identifier
c:\jake\projects\roguelike\utility.cpp(45) : error C2065: 'BLACK' : undeclared identifier
c:\jake\projects\roguelike\utility.cpp(45) : error C2065: 'WHITE' : undeclared identifier
c:\jake\projects\roguelike\utility.cpp(48) : error C2653: 'Color' : is not a class or namespace name
It isn't pretty and it's mostly uncommented, but I'm hoping that the problem is so obvious and trivial that you'll recognize it immediately. This is only one file that is having trouble. Of course, it works.... well, compiles at least, in Dev-C++, so the problem might not be in my code at all.
-
Your include guards look strange. From wiki:
"Different naming conventions for the guard macro may be used by different programmers. Other common forms of the above example include GRANDFATHER_INCLUDED and _GRANDFATHER_H. However, _GRANDFATHER_H and __GRANDFATHER_H are prohibited by the C++ standard because identifiers beginning with one or more underscores are reserved names."
Try to change them to:
#ifndef UTILITY_H
#define UTILITY_H
etc..
-
That did it. Thanks, Krice. I wonder why Dev-C++ never complained. There's some other stuff I need to clean up, but it's mostly just signed/unsigned mismatches in my for() loops, which won't take long to correct.
EDIT: All right, it stopped complaining about those. Whatever.
-
I wonder why Dev-C++ never complained.
GCC is probably doing things slightly different way. I also noticed that VC++ was better at catching errors, but it also depends on warning settings. In VC++ I think W3 (default) is the best option, because W4 (highest) is warning about all type conversions.. still I think it's good to fix those unsigned/signed warnings in important places like for loops.
-
That did it. Thanks, Krice. I wonder why Dev-C++ never complained. There's some other stuff I need to clean up, but it's mostly just signed/unsigned mismatches in my for() loops, which won't take long to correct.
EDIT: All right, it stopped complaining about those. Whatever.
Warnings will only appear when recompiling. They are not a problem but its best to fix them so you dont miss an important warning amongst other warnings. Best practice is to get rid of all warnings.
-
Warnings are so useless... either something is an error or its not - there is no maybe.
-
Warnings are so useless... either something is an error or its not - there is no maybe.
Warnings are often related to poorly written code that may trigger a bug in certain situation. I think those are much worse than straight errors.
-
Krice is right.
Sometimes you write perfectly logical code, but the same code used another way will produce the incorrect behaviour. The compiler doesn't know what you intend so it warnings to tell you that this code may have bugs.
A simple example is converting a float to an int. You lose data doing so, but most of the time thats what you want. So the compiler just reminds you to put explicit type conversion in your code, now the compiler knows what you intended.
-
Thats what i say; warnings are useless; either its an error, or its not. If the compiler knows that it could probably lead to a bug, its an error.... If something happens implicitly converted to a less exact format, its a error.
-
If the compiler knows that it could probably lead to a bug, its an error....
Warning and error are two different things for the compiler, no matter how you might understand it.