Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
TSDK
Nov 24, 2003

I got a wooden uploading this one

Staggy posted:

If I build in Debug I get that error, but if I switch to Release to build I get
An unresolved WinMain means that you've written it as standard C/C++ with a main function, but are compiling it with SubSystem (Properties->Linker->System) set to Windows instead of Console.

Adbot
ADBOT LOVES YOU

Staggy
Mar 20, 2008

Said little bitch, you can't fuck with me if you wanted to
These expensive
These is red bottoms
These is bloody shoes


I changed it to Console, but now I get

quote:

MSVCRT.lib(crtexe.obj) : error LNK2001: unresolved external symbol _main
C:\Documents and Settings\Dan\My Documents\Visual Studio 2008\Projects\SDL_Game\Release\SDL_Game.exe : fatal error LNK1120: 1 unresolved externals
instead.

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
Doesn't the SDL DLL define a main() (or maybe it's WinMain()) for you? Is your main of the type int main(int,char*[])? I thought these linker gotchas were mentioned in the SDL Windows FAQs, but I can't re-find it.

Staggy
Mar 20, 2008

Said little bitch, you can't fuck with me if you wanted to
These expensive
These is red bottoms
These is bloody shoes


Yeah, I'm using main as

quote:

int main( int argc, char* args[] )

EDIT: I think I've got it solved. I cleared the Linker->Input->Additional Dependencies settings, and then added the links back in, and it started working. Strange.

Well thanks for all the help anyway. It's amazing to get such a rapid response, especially on a website that isn't specifically geared towards programming. (Yes I am aware this is the programming sub forum, shut up.)

Staggy fucked around with this message at 15:51 on May 30, 2008

vanjalolz
Oct 31, 2006

Ha Ha Ha HaHa Ha
Knowing that made up statistics are useless, I'm guessing that 50% of the saforums traffic is programmers bored at work :P

slovach
Oct 6, 2005
Lennie Fuckin' Briscoe

Boz0r posted:

I'm trying to write a program that could cause my Windows XP computer to do a BSOD. This is apparently harder than I had imagined. Does anyone have a short code snippet that could do this?


With admin access. I'm just trying to kill my dell.

Could you give me a little more in-depth hint? I'm not too hot on C++ yet.

A little late on the response but...

Easiest way in my opinion is calling KeBugCheck, you need to do it from a driver but that's easy.

Staggy posted:

I changed it to Console, but now I get

instead.

Are you trying to avoid the CRT somehow?

Try what the linker expects, it'll look for the function and use it as the entry point, like:

code:
void __cdecl WinMainCRTStartup(void){
	ExitProcess(WinMain(GetModuleHandle(NULL), NULL, NULL, SW_NORMAL));
}
If it's a console program, use mainCRTStartup instead and change it as you'd expect.

slovach fucked around with this message at 02:17 on Jun 2, 2008

Arms_Akimbo
Sep 29, 2006

It's so damn...literal.
nm, i got it. and this was too poorly worded to help anybody else anyway

Arms_Akimbo fucked around with this message at 06:51 on Jun 2, 2008

Clanpot Shake
Aug 10, 2006
shake shake!

I've got a little problem I need solved. I'm coding in C++ and need to connect to a Microsoft SQL database, but I can't use .NET, I can only use straight C++. How do I go about doing this?

ehnus
Apr 16, 2003

Now you're thinking with portals!

Clanpot Shake posted:

I've got a little problem I need solved. I'm coding in C++ and need to connect to a Microsoft SQL database, but I can't use .NET, I can only use straight C++. How do I go about doing this?

Microsoft's ODBC documentation is probably a good place to start: http://msdn.microsoft.com/en-us/library/ms710252%28VS.85%29.aspx

This functionality should be included in the Windows Platform SDK

Insurrectum
Nov 1, 2005

Alright, so I'm trying to teach myself C++, and to begin I just wanted to write a simple adventure game program that just creates a series of rooms with descriptions and North, South, East, and West rooms. I'm really just trying to get a feel for pointers, since I never used them in Java. I know I'm doing something fundamentally wrong, but I just can't figure out exactly what.

code:
#include <cstdlib>
#include <iostream>
#include <string>

using namespace std;

class Room {
    public:
        Room();
        ~Room();
        void setd(string str, Room room);
        void getd();
        void setnorthroom(Room north);
        void setsouthroom(Room south);
        void setwestroom(Room west);
        void seteastroom(Room east);
        void checkrooms();
        Room getnorthroom();
        Room getsouthroom();
        Room getwestroom();
        Room geteastroom();
        string description;
        Room *nroom;
        Room *sroom;
        Room *wroom;
        Room *eroom;
        int hasnorth;
        int hassouth;
        int haseast;
        int haswest;
};

Room::Room() { 
    int hasnorth = 0;
    int hassouth = 0;
    int haseast = 0;
    int haswest = 0;
    Room *nroom = NULL;
    Room *sroom = NULL;
    Room *wroom = NULL;
    Room *eroom = NULL;
}

Room::~Room() { }

void Room::setd(string str, Room room){
    description = str;
}

void Room::getd(){
    cout<<description<<endl;
}

void Room::setnorthroom(Room north) {
    nroom = &north;
    hasnorth = 1;
    if (hassouth == 0) 
        setsouthroom(north);
}

void Room::setsouthroom(Room south) {
    sroom = &south;
    hassouth = 1;
    if (hasnorth == 0)
        setnorthroom(south);
}

void Room::seteastroom(Room east) {
    eroom = &east;
    haseast = 1;
    if (haswest == 0)
        setwestroom(east);
}

void Room::setwestroom(Room west) {
    wroom = &west;
    haswest = 1;
    if (haseast == 0)
        seteastroom(west);
}

Room Room::getnorthroom() {
    return *nroom;
}
Room Room::getsouthroom() {
    return *sroom;
}
Room Room::geteastroom() {
    return *eroom;
}
Room Room::getwestroom() {
    return *wroom;
}

void Room::checkrooms() {
    if (nroom != NULL)
        cout<<"There is a door north"<<endl;
    if (sroom != NULL)
        cout<<"There is a door south"<<endl;
    if (eroom != NULL)
        cout<<"There is. a door east"<<endl;
    if (wroom != NULL)
        cout<<"There is a door west"<<endl; 
}   

int main()
{
    Room adv;
    adv.setd("This is an empty room", adv);
    adv.getd();
    Room adv2;
    adv2.checkrooms();
    adv.setnorthroom(adv2);
    adv2.checkrooms();
    system("PAUSE");
    return EXIT_SUCCESS;
}
Here's the output.

code:
This is an empty room
There is a door north
There is a door south
There is. a door east
There is a door west
There is a door north
There is a door south
There is. a door east
There is a door west
Also, any other tips in general?

floWenoL
Oct 23, 2002

Insurrectum posted:

Alright, so I'm trying to teach myself C++, and to begin I just wanted to write a simple adventure game program that just creates a series of rooms with descriptions and North, South, East, and West rooms. I'm really just trying to get a feel for pointers, since I never used them in Java.

Yes you have, they're just called 'references' and you can't do arithmetic on them. The problem is that you're thinking that "Room" is a reference type like in Java whereas in C++ it's actually a value type; that is, getnorthroom() etc. should all return Room * and setnorthroom() etc. should all take in Room *.

Insurrectum
Nov 1, 2005

I changed around my code to make those take and give pointers (I'm not sure if I completely understood your comments, but correct me if I didn't).

code:
#include <cstdlib>
#include <iostream>
#include <string>

using namespace std;

class Room {
    public:
        Room();
        ~Room();
        void setd(string str, Room room);
        void getd();
        void setnorthroom(Room *north);
        void setsouthroom(Room *south);
        void setwestroom(Room *west);
        void seteastroom(Room *east);
        void checkrooms();
        Room getnorthroom();
        Room getsouthroom();
        Room getwestroom();
        Room geteastroom();
        string description;
        Room *nroom;
        Room *sroom;
        Room *wroom;
        Room *eroom;
        int hasnorth;
        int hassouth;
        int haseast;
        int haswest;
};

Room::Room() { 
    int hasnorth = 0;
    int hassouth = 0;
    int haseast = 0;
    int haswest = 0;
    Room *nroom = NULL;
    Room *sroom = NULL;
    Room *wroom = NULL;
    Room *eroom = NULL;
}

Room::~Room() { }

void Room::setd(string str, Room room){
    description = str;
}

void Room::getd(){
    cout<<description<<endl;
}

void Room::setnorthroom(Room *north) {
    nroom = north;
    hasnorth = 1;
    if (hassouth == 0) 
        setsouthroom(north);
}

void Room::setsouthroom(Room *south) {
    sroom = south;
    hassouth = 1;
    if (hasnorth == 0)
        setnorthroom(south);
}

void Room::seteastroom(Room *east) {
    eroom = east;
    haseast = 1;
    if (haswest == 0)
        setwestroom(east);
}

void Room::setwestroom(Room *west) {
    wroom = west;
    haswest = 1;
    if (haseast == 0)
        seteastroom(west);
}

Room Room::getnorthroom() {
    return *nroom;
}
Room Room::getsouthroom() {
    return *sroom;
}
Room Room::geteastroom() {
    return *eroom;
}
Room Room::getwestroom() {
    return *wroom;
}

void Room::checkrooms() {
    if (nroom != NULL)
        cout<<"There is a door north"<<endl;
    if (sroom != NULL)
        cout<<"There is a door south"<<endl;
    if (eroom != NULL)
        cout<<"There is a door east"<<endl;
    if (wroom != NULL)
        cout<<"There is a door west"<<endl; 
}   

int main()
{
    Room adv;
    adv.setd("This is an empty room", adv);
    adv.getd();
    Room adv2;
    adv2.checkrooms();
    adv.setnorthroom(&adv2);
    adv2.checkrooms();
    system("PAUSE");
    return EXIT_SUCCESS;
}
However, my output is still:

code:
This is an empty room
There is a door north
There is a door south
There is a door east
There is a door west
There is a door north
There is a door south
There is a door east
There is a door west
Where I would expect it to be:

code:
This is an empty room
There is a door south
What am I doing wrong?

snack soul
Jul 6, 2005

Insurrectum posted:


code:
class Room {
    public:
        ...
        string description;
        Room *nroom;
        Room *sroom;
        Room *wroom;
        Room *eroom;
        int hasnorth;
        int hassouth;
        int haseast;
        int haswest;
};

Room::Room() { 
    int hasnorth = 0;
    int hassouth = 0;
    int haseast = 0;
    int haswest = 0;
    Room *nroom = NULL;
    Room *sroom = NULL;
    Room *wroom = NULL;
    Room *eroom = NULL;
}

The variables you're trying to initialize in your constructor are already class members, so there's no need to re-declare them. As is, you're creating and initializing temporary variables local to your constructor, which is effectively masking the variables you really want to set.

code:
Room::Room() { 
    hasnorth = 0;
    hassouth = 0;
    haseast = 0;
    haswest = 0;
    nroom = NULL;
    sroom = NULL;
    wroom = NULL;
    eroom = NULL;
}
Or better yet, a proper initializer list:

code:
Room::Room() 
: hasnorth(0), hassouth(0), haseast(0), haswest(0),
  nroom(NULL), sroom(NULL), wroom(NULL), eroom(NULL) { 
}

Insurrectum posted:

code:
void Room::setd(string str, Room room){
    description = str;
}

void Room::getd(){
    cout<<description<<endl;
}

When you're passing around classes (like string, or especially anything heavy-weight) that you know won't be modified (only copied), it's more efficient to pass a constant reference. Internally you're only passing the address, as opposed to the entire class and all of it's associated data, but it cannot be modified, and you don't have to use the typical pointer syntax.

I would also have getd simply return the description, as opposed to printing it out. It makes more sense, given the name (get*), and you may want to store or modify the value outside of the class later.

code:
void Room::setd(const string &str, Room room){
    description = str;
}

Insurrectum posted:

code:
void Room::setnorthroom(Room north) {
    nroom = &north;
    hasnorth = 1;
    if (hassouth == 0) 
        setsouthroom(north);
}

The variable "north" is temporary. Taking it's address is a bad idea, as it will just point to junk stack space once the method returns. Either pass in north as a pointer (Room *north), or create a new object inside of setnorthroom() and copy the contents from north to your new copy.

You should also make sure to delete all the variables you dynamically allocate. Best place to do this would be in your constructor, ie


code:

Room::~Room() { 
    if(nroom != NULL) {
        delete nroom;
        nroom = NULL;
    }
    // etc, etc...
}

You could also eliminate your 'has*' variables by just checking whether or not the 'room' variable in question is NULL. If nroom is NULL, there's no north room, otherwise there is.

snack soul fucked around with this message at 01:07 on Jun 4, 2008

Insurrectum
Nov 1, 2005

^^^Thanks, I didn't know about the initializer lists. I deleted the get*room functions because I wasn't actually using them, and I changed the getd to printd, because that's all I wanted the function to do.

code:
#include <cstdlib>
#include <iostream>
#include <string>

using namespace std;

class Room {
    public:
        Room();
        ~Room();
        void setd(const string &str, Room room);
        void printd();
        void setnorthroom(Room *north);
        void setsouthroom(Room *south);
        void setwestroom(Room *west);
        void seteastroom(Room *east);
        void checkrooms();
        string description;
        Room *nroom;
        Room *sroom;
        Room *wroom;
        Room *eroom;
};

Room::Room() : nroom(NULL), sroom(NULL), eroom(NULL), wroom(NULL) { 
    
}

Room::~Room() { 
    if (nroom!=NULL) {
        delete nroom;
        nroom = NULL;
    }
}

void Room::setd(const string &str, Room room){
    description = str;
}

void Room::printd(){
    cout<<description<<endl;
}

void Room::setnorthroom(Room *north) {
    nroom = north;
    if (sroom == NULL) 
        setsouthroom(north);
}

void Room::setsouthroom(Room *south) {
    sroom = south;
    if (nroom == NULL)
        setnorthroom(south);
}

void Room::seteastroom(Room *east) {
    eroom = east;
    if (wroom == NULL)
        setwestroom(east);
}

void Room::setwestroom(Room *west) {
    wroom = west;
    if (eroom == NULL)
        seteastroom(west);
}

void Room::checkrooms() {
    if (nroom != NULL)
        cout<<"There is a door north"<<endl;
    if (sroom != NULL)
        cout<<"There is a door south"<<endl;
    if (eroom != NULL)
        cout<<"There is a door east"<<endl;
    if (wroom != NULL)
        cout<<"There is a door west"<<endl; 
}   

int main()
{
    Room adv;
    adv.setd("This is an empty room", adv);
    adv.printd();
    Room adv2;
    adv2.checkrooms();
    adv.setnorthroom(&adv2);
    adv2.checkrooms();
    system("PAUSE");
    return EXIT_SUCCESS;
}
This is what I'm getting now:

code:
This is an empty room
Press any key to continue . . .

Insurrectum fucked around with this message at 02:05 on Jun 4, 2008

POKEMAN SAM
Jul 8, 2004
Edit: Nevermind, checkexits or whatever prints. I was confused by the name of the function.

Incoherence
May 22, 2004

POYO AND TEAR
Your problem is an error in the logic of your setXroom() method. What you seem to want is for a.setnorthroom(&b) to set a.northroom = b and set b.southroom = a, but that's not what your code is doing at all. What setnorthroom() actually does when you call it in main() is that it sets adv.northroom AND adv.southroom to adv2, but does not change adv2.

Troglepus
Jan 10, 2007
A man for all and none.
I am new to C++(just started looking at it for a silly hw) but I know some c. Anywho,
I have a question, I am creating a class and I want to include a helper function that is not included in the class definition. I am calling it from one of my constructors and I am getting a "not defined in this scope" error. I can't change the header file where the class is defined so how do I fix this error.

edit: Sorry I am silly I figured it out.

Troglepus fucked around with this message at 06:10 on Jun 4, 2008

Insurrectum
Nov 1, 2005

So I changed the set*room code to just do the one function of setting the pointer, and that works fine. I'm trying to implement a function linkrooms() that does this so the rooms are always done in pairs, but it doesn't seem to be working. The switch case statement is working, so it's something wrong with my basic understanding of the function (which works fine outside of linkrooms).

code:
void Room::setnorthroom(Room *north) {
    nroom = north;
}

void Room::setsouthroom(Room *south) {
    sroom = south;
}

void Room::seteastroom(Room *east) {
    eroom = east;
}

void Room::setwestroom(Room *west) {
    wroom = west;
}

...

void linkrooms(Room room, Room room2, char d) {
    switch (d) {
        case 'n':
            room.setnorthroom(&room2);
            room2.setsouthroom(&room);
            break;
        case 's':
            room.setsouthroom(&room2);
            room2.setnorthroom(&room);
            break;
        case 'e':
            room.seteastroom(&room2);
            room2.setwestroom(&room);
            break;
        case 'w':
            room.setwestroom(&room2);
            room2.seteastroom(&room);
            break;
        default:
            cout<<"SOMETHINGS WRONG";
            break;
    }
}

POKEMAN SAM
Jul 8, 2004
Whenever you're using a Room in a parameter or return value, do Room * so it affects the real one, not the copy.

Insurrectum
Nov 1, 2005

Ugg boots posted:

Whenever you're using a Room in a parameter or return value, do Room * so it affects the real one, not the copy.

Like this? I assume not, because it doesn't compile.

code:
void linkrooms(Room *room, Room *room2, char d) {
    switch (d) {
        case 'n':
            room.setnorthroom(&room2);
            room2.setsouthroom(&room);
            break;

Vanadium
Jan 8, 2005

Insurrectum posted:

Like this? I assume not, because it doesn't compile.

code:
void linkrooms(Room *room, Room *room2, char d) {
    switch (d) {
        case 'n':
            room.setnorthroom(&room2);
            room2.setsouthroom(&room);
            break;

You need to dereference the pointer to get the object it is pointing to.
(*room).setnorthroom(&room2); or, more concise, room->setnorthroom(&room2);.

A basic book or tutorial on C(++) should cover all this so you can get on with the actual program. :)

Insurrectum
Nov 1, 2005

Vanadium posted:

You need to dereference the pointer to get the object it is pointing to.
(*room).setnorthroom(&room2); or, more concise, room->setnorthroom(&room2);.

A basic book or tutorial on C(++) should cover all this so you can get on with the actual program. :)

Thanks! The room creation/connection part works now. Well, mostly. I'm guessing there's some kind of memory issue, as the program never exits gracefully... it always locks up.
code:
int main()
{
    Room adv;
    adv.setd("This is an empty room");
    adv.printd();
    Room adv2;
    adv2.setd("This is another empty room");
    adv2.checkrooms();
    adv2.printd();
    system("PAUSE");
    linkrooms(&adv, &adv2, 'n');
    cout<<"checking first room"<<endl;
    adv.checkrooms();
    cout<<"checking second room"<<endl;
    adv2.checkrooms();
    system("PAUSE");
    return EXIT_SUCCESS;
}
code:
This is an empty room
This is another empty room

checking first room
There is a door north

checking second room
There is a door south
I've actually read a bunch of tutorials on C++, but I'm a "learning by doing" type of person, so I find the best way to learn is to just undertake some project.

TheSleeper
Feb 20, 2003
system("PAUSE"); waits for input, so you'll have to press enter before it'll exit.

vanjalolz
Oct 31, 2006

Ha Ha Ha HaHa Ha

Insurrectum posted:

Like this? I assume not, because it doesn't compile.

code:
void linkrooms(Room *room, Room *room2, char d) {
    switch (d) {
        case 'n':
            room.setnorthroom(&room2);
            room2.setsouthroom(&room);
            break;

Like Vanadium said above, you need to do room->setnorthroom
and because the input to the function is now a pointer, you don't need to dereference the parameters to set*room

Ie.

code:
void linkrooms(Room *room, Room *room2, char d) {
    switch (d) {
        case 'n':
            room->setnorthroom([b]room2[/b]);
            room2->setsouthroom([b]room[/b]);
            break;
[/quote]

Creepy Doll
Apr 20, 2008

Insurrectum posted:

Thanks! The room creation/connection part works now. Well, mostly. I'm guessing there's some kind of memory issue, as the program never exits gracefully... it always locks up.
code:
int main()
{
    Room adv;
    adv.setd("This is an empty room");
    adv.printd();
    Room adv2;
    adv2.setd("This is another empty room");
    adv2.checkrooms();
    adv2.printd();
    system("PAUSE");
    linkrooms(&adv, &adv2, 'n');
    cout<<"checking first room"<<endl;
    adv.checkrooms();
    cout<<"checking second room"<<endl;
    adv2.checkrooms();
    system("PAUSE");
    return EXIT_SUCCESS;
}
code:
This is an empty room
This is another empty room

checking first room
There is a door north

checking second room
There is a door south
I've actually read a bunch of tutorials on C++, but I'm a "learning by doing" type of person, so I find the best way to learn is to just undertake some project.

All mentions forthwith of C/C++ referer to either of the two separate languages, whichever you prefer.

I really don't want to sound condescending but I do think you really should look into reading through a good foundation book on C/C++ or at least an article or two on pointers, and how C/C++ actually handles memory(the stack and heap), as well as how and when it is allocated and deallocated, as a lot of it is not obvious and likely to cause headaches later on.

A lot of programming languages really hold your hand when it comes to memory allocation, garbage collection, and you don't need to know it. However, ultimately in C/C++ if you don't know it, it can make your life a whole lot more uncomfortable. If however you do know it and understand it, it allows for clever memory manipulation and optimisations that no other language will let you near. I've always considered C/C++ the language for control freaks who aren't quite mad enough to go for raw assembly.

If you insist on learning it by practice though, take some time to understand how to use a debugger, look at your pointers, look at your memory and see what exactly your code is doing.

To avoid just being an overbearing rear end in a top hat, hopefully I can clarify some stuff others touched on(you probably know most of this but don't want to skip anything important):
A pointer (Room* myRoom) points to a raw position in memory. Printing it out will just give you something that looks like a random hex number(the exception to this is if you use a pointer to a character(char*)... Most output functions will by default print out characters from that location until reaching a null character or character limit...basically the rawest form of a string).
If you dereference that pointer(either (*myRoom)) you will access memory stored at the destination of the pointer. This is you actual room data. The -> is just a shortcut for(*myRoom).whatever(which becomes myRoom->whatever), though it's of course faster to write and generally makes for more readable code, so use it!

A function will make copies(the manufacturing of which in C++ can be customised using the copy constructor) of parameters to the stack(http://en.wikipedia.org/wiki/Call_stack if you're interested in the grittier stuff) when you call it. The called function will then access these copies. So any change you make to the actual parameters, will be gone once the function exits and the parameter is out of context. However, a copy of a pointer still points to the same memory, so if you dererence the pointer and then change the contents of the memory it is pointing to, the change stays, even as the copy of the pointer goes out of context. If you want to change what a pointer points to, you will of course need a pointer to a pointer!

Summary: C/C++ is awesome and the power it grants you kicks rear end. But it will give you horrible headaches at time, and understanding how this stuff works and why will help a lot when solving problems(and avoiding them turning up in the first place). I hope I've convinced you to take a little time to learn more about the workings which are much easier to get a basic grasp of from books, and then reinforce through doing. Also, try using a debugger to track the stuff that seems to be going quirky. Just set a breakpoint before the last place you know where the wrong variable was right, and step through until it is wrong.

edited for C/C++ clarity

Creepy Doll fucked around with this message at 16:53 on Jun 4, 2008

MarsMattel
May 25, 2001

God, I've heard about those cults Ted. People dressing up in black and saying Our Lord's going to come back and save us all.
Creepy Doll: There is no "C/C++" language. They have similarities, but they are not the same thing and blidly lumping them together and talking about the virtues and uses for a non-existant language does no one any favours.

Insurrectum: you don't need to check for NULL before deleting a pointer, deleting a null pointer is perfectly acceptable. http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.8

Creepy Doll
Apr 20, 2008

MarsMattel posted:

Creepy Doll: There is no "C/C++" language. They have similarities, but they are not the same thing and blidly lumping them together and talking about the virtues and uses for a non-existant language does no one any favours.

Insurrectum: you don't need to check for NULL before deleting a pointer, deleting a null pointer is perfectly acceptable. http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.8

Pardon me for using shorthand. I generally write C/C++ because I honestly don't care to write a treatise on the differences between the two which are quite apparent to anyone who actually tries to use one or the other. Writing C/C++ is simply short for "C or C++". Pointers are featured in both and function identically in both. Plenty of books that cover both languages also use this possibly slightly misleading term for convenience. Are they lumping the two together as well? Admittedly I blundered in mentioning copy constructors which are indeed exclusive to C++, and will admit that could be misleading, though I don't really think your response needed to be made in the belittling manner you wrote it in, when the issue is a minor one, and the actual meat of the content is correct.

edit: To be less confrontational \/\/\/

Creepy Doll fucked around with this message at 16:54 on Jun 4, 2008

6174
Dec 4, 2004

Creepy Doll posted:

I think your behaviour is pretty reminiscent to that of a grammar nazi correcting a typo(also known as nitpicking).

C/C++ is not a language. Your post implied that it was. Just because there are similarities between them does not mean that lumping them together is reasonable in all contexts. In particular your post was addressed at someone who clearly is very new to C++ and using C/C++ is needlessly confusing. This "nitpicking", as you deride it, is not only appropriate here, it should be encouraged. Moreover, alluding that MarsMattel's comment is reminiscent of a grammar nazi is fatuous. If you have a point, make it, making a personal attack on someone else because you messed up reflects very poorly on you.

Staggy
Mar 20, 2008

Said little bitch, you can't fuck with me if you wanted to
These expensive
These is red bottoms
These is bloody shoes


6174 posted:

C/C++ is not a language. Your post implied that it was. Just because there are similarities between them does not mean that lumping them together is reasonable in all contexts. In particular your post was addressed at someone who clearly is very new to C++ and using C/C++ is needlessly confusing. This "nitpicking", as you deride it, is not only appropriate here, it should be encouraged. Moreover, alluding that MarsMattel's comment is reminiscent of a grammar nazi is fatuous. If you have a point, make it, making a personal attack on someone else because you messed up reflects very poorly on you.

I really don't see what the problem with his reply was. I mean he did say C/C++. C/C++. As in, 'C or C++'. In no way has he implied that 'C/C++' is a language of it's own; instead, he lumped two similar languages together because they both share similar features, and he wanted to explain that these features apply to both of them. This was a perfect context.

I'd agree with the whole 'grammar nazi' point. Such a stupid level of nitpicking is ridiculous. As for the whole 'beginner being confused' issue... I've always seen C and C++ lumped together as C/C++. It's not confusing. Anyone who can recognise basic English grammar can see the significance of the slash.

Also, thank you Creepy Doll. pointers have always been a sore spot for me, and it's nice to see them explained so clearly.

snack soul
Jul 6, 2005

Insurrectum posted:

code:
Room::~Room() { 
    if (nroom!=NULL) {
        delete nroom;
        nroom = NULL;
    }
}

This is likely the reason your program crashes upon exit. I may have been a little unclear in my explanation as to when and why you should do this. The delete keyword is only used for freeing memory that you allocated dynamically. You should never attempt to delete/free memory that is on the stack (locals/autos) or that is static.

code:
MyObject *obj = new MyObject;
delete obj; /* this is ok */

MyObject *obj = new MyObject[N];
delete[]; /* this is ok - notice the use of [] when deleting arrays */
When dealing with cleaning up memory passed into a function or method, you need to be very explicit about who's responsibility it is to free it (if at all).

Since your room class (as is) attempts to delete the north/south/east/west pointers in it's destructor, you need to make sure that those pointers were dynamically allocated (and they presently are not).


code:
Room adv; 
adv.setd("This is an empty room", adv); 
adv.printd(); 
Room adv2;
adv2.checkrooms(); 
adv.setnorthroom(&adv2);
This is wrong because you're pointing to the variable "adv2", which was not dynamically allocated. Attempting to free/delete it is erroneous.

code:
Room adv;
adv.setnorthroom(new Room);
Now you can delete your north room pointer, but you've introduced more problems. If you call setnorthroom() with another object, you can't simply reassign the existing pointer to the new object without leaking memory. You need to check if you're already pointing to something, delete that object if an only if it is valid, THEN perform your assignment.

Of course it still won't be a very safe design because once you have a relatively complex network of different rooms pointing to one another, what happens if you were to assign a new north room, causing the previously stored room to be deleted? Other rooms in your network now may be pointing to invalid memory.

As good as hands on learning is, it may help to have a more solid understanding of pointers and memory management before doing a project like this. Check out "Accelerated C++", as it's a very good introductory text. Books on C are also pretty useful for dealing with the lower level "C-style" aspects of C++. "The C Programming Language" should be required reading for anyone interested in programming.

The arguments above make a good point in that you really shouldn't lump C and C++ together. C++ is (for the most part) a superset of C, but that doesn't mean it's a good idea to treat it like "C with classes". Higher level facilities like smart pointers and generic containers exist for a reason, and are generally the preferred solution when using C++ over C, but understanding the nitty gritty details of how everything works on a lower level is just as important.

Insurrectum
Nov 1, 2005

Creepy Doll posted:

A function will make copies(the manufacturing of which in C++ can be customised using the copy constructor) of parameters to the stack(http://en.wikipedia.org/wiki/Call_stack if you're interested in the grittier stuff) when you call it. The called function will then access these copies. So any change you make to the actual parameters, will be gone once the function exits and the parameter is out of context. However, a copy of a pointer still points to the same memory, so if you dererence the pointer and then change the contents of the memory it is pointing to, the change stays, even as the copy of the pointer goes out of context. If you want to change what a pointer points to, you will of course need a pointer to a pointer!

Hey, thanks for this. I have read several tutorials on pointers and I even have a C++ book, but even after reading all of that this one post was much more revealing than everything I've read so far. Coming from Java one of the big things I knew was different was memory management and pointers so I'm really just trying to attack that first.

vvvvThanks, these kind of small tips are why I like asking here

Insurrectum fucked around with this message at 21:37 on Jun 4, 2008

slovach
Oct 6, 2005
Lennie Fuckin' Briscoe

Insurrectum posted:

Thanks! The room creation/connection part works now. Well, mostly. I'm guessing there's some kind of memory issue, as the program never exits gracefully... it always locks up.
code:
system("PAUSE");}

some random advice, but I'd try to avoid using system, there's a lot of overhead.

try something like this if you need to wait for user input.
code:
cin.sync();
cin.ingore();

Paniolo
Oct 9, 2007

Heads will roll.
Here's another tip - instead of having "wroom, nroom, etc.", try this:

code:
const unsigned int North = 0, East = 1, South = 2, West = 3, MaxDirections = 4;

// In your Room class
Room* links[MaxDirections];

// Instead of setnorthroom, etc.
void Room::link(Room* dest, unsigned int dir) {
   assert(dir < MaxDirections);
   links[dir] = dest;
}
Not only does this remove a lot of your boilerplate code but it will make it easier for you to add different directions (such as Up, Down, Northwest, etc.)

deadjb
Aug 11, 2002

Paniolo posted:

Here's another tip - instead of having "wroom, nroom, etc.", try this:

code:
const unsigned int North = 0, East = 1, South = 2, West = 3, MaxDirections = 4;
Not only does this remove a lot of your boilerplate code but it will make it easier for you to add different directions (such as Up, Down, Northwest, etc.)

It's nice to put that sort of stuff in an enum, since it's a bit cleaner looking and conceptually makes sense. That may just be my stylistic preference, though.

Smackbilly
Jan 3, 2001
What kind of a name is Pizza Organ! anyway?

SkankerX posted:

It's nice to put that sort of stuff in an enum, since it's a bit cleaner looking and conceptually makes sense. That may just be my stylistic preference, though.

Tbe biggest advantage is that enums are typesafe, so you will not need that extra "assert" statement to check that the parameter is in the valid range. If you have:

code:
enum Directions { North = 0, South, East, West };

void Room::link(Room* dest, Direction dir) {
  links[dir] = dest;
}
The compiler will automatically complain if you try to pass anything other than one of the valid values as the second argument.

Also note that there is no problem with using an enum value to index an array - enum values are automatically promoted to integers. Note that I have assigned North = 0 to ensure that the numbers assigned to the enum values begin from zero (since I'm not sure if that's mandated by the standard or not).

But you will still need a constant recording how many valid values there are for the purpose of declaring the links[] array. Unfortunately there is no way to simply query an enum type and ask it how many valid values there are.

TheSleeper
Feb 20, 2003
Yea, but if you define your constant right next to your enum, it'll be easy to keep them in sync with each other.

Lexical Unit
Sep 16, 2003

Smackbilly posted:

But you will still need a constant recording how many valid values there are for the purpose of declaring the links[] array. Unfortunately there is no way to simply query an enum type and ask it how many valid values there are.

At my job I always see this sort of thing:

code:
enum Directions
{
  eNorth, eSouth, eWest, eEast, ..., 
  kNumDirections
};
Not sure how I feel about it.

ColdPie
Jun 9, 2006

Lexical Unit posted:

At my job I always see this sort of thing:

code:
enum Directions
{
  eNorth, eSouth, eWest, eEast, ..., 
  kNumDirections
};
Not sure how I feel about it.

I use that all the time and see no reason why it would be considered bad practice given that the first enum is explicitly defined to be 0 (or is that actually part of the standard?). It's pretty obvious what's going on and completely removes the maintenance for keeping track of the number of elements.

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
From the C standard:

quote:

An enumerator with = defines its enumeration constant as the value of the constant expression. If the first enumerator has no =, the value of its enumeration constant is 0. Each subsequent enumerator with no = defines its enumeration constant as the value of the constant expression obtained by adding 1 to the value of the previous enumeration constant. (The use of enumerators with = may produce enumeration constants with values that duplicate other values in the same enumeration.)
So, that method is fine unless your enum has explicit assignments in it.

Adbot
ADBOT LOVES YOU

floWenoL
Oct 23, 2002

ColdPie posted:

I use that all the time and see no reason why it would be considered bad practice given that the first enum is explicitly defined to be 0 (or is that actually part of the standard?). It's pretty obvious what's going on and completely removes the maintenance for keeping track of the number of elements.

On the other hand, it introduces an invalid value (kNumWhatever) that is treated like a valid value.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply