![]() |
|
#1
|
|||
|
|||
Classes and allocating memoryI'm making a headrer file for a card game, ideally what i would like to have happen is the user of this file define how many cards are in the deck and then define the specifics of each card. I have a class called 'deck', and a structure called 'card'. The class 'deck' has an undefined array of cards.
ex: DECK PlayingCards(10); // allowing 10 cards to be in the deck. CPP / C++ / C Code:
and here is the 'deck' constructor: CPP / C++ / C Code:
this compiles without error, but when i run it, it gives me an 'unhandeled win32 app' error. Can someone please tell me what i'm doing wrong? |
|||
|
#2
|
||||
|
||||
Re: Classes and allocating memoryAre you trying to create a console application or a Windows application? If console, you created the project incorrectly.
Other than that, can't tell from the information given. __________________
During the election they said Obama could only be elected when pigs fly. Well, we currently have an epidemic of Swine Flu. Coincidence? |
|
#3
|
|||
|
|||
Re: Classes and allocating memoryQuote:
You're using C++ incorrectly. You don't understand that the importance of hiding your data. Everything you've done is public. You aren't using containers, rather, have elected to self-manage an array. Here is a little hint. If you know that you don't know how to write decent C++ code, use as many standard library features of the language as possible. Here is a crude example of a PlayingCard class that, unfortunately, has no inheritance chain. CPP / C++ / C Code:
Your code looks like you're trying to be lazy about implementing your "classes." They are about 1 step below novice. I'm not trying to be rude, but your code is UGLY. You can't fix a turd. Throw it away and start over. First learn how to design a good class, then write code to implement one. While my example won't necessarily solve any of your problems, it may help you to consider some of the features of C++ that pertain to class design. My recommendation is that you at least attempt to employ some of those features in your own class designs. If you're interested in discussing good class design, let's talk about it. That's one of the reasons for this forum. :davis: |
|
#4
|
|||
|
|||
Re: Classes and allocating memoryI doubt the code you gave would compile. Why don't you provide a full program in which you encounter the described error. I don't mean posting hundreds of lines of code just to illustrate the behaviour, but post a minimal program.
You don't provide a destructor, you don't provide any methods for inserting data, you don't provide any methods for showing the data etc. So far it looks like, as davis said, that you just create a class just for the fun of it. You could as well just create an array of those structures. That would actually be a lot easier too. EDIT You don't need to provide a destructor, as it will be automatically provided for you, but if you provide a declaration for the destructor, then you need to also provide the definition. In this case it's recommended to provide a destructor to delete the memory allocated. "If you don't know you need it, you don't" often applies to being a software musician and I think it applies to programming too. |
|
#5
|
|||
|
|||
Re: Classes and allocating memoryall i want to know is weather you can allocate memory in a class through the constructor and how. and this is the first time i've actually tried to use a class so tell me proper technique.
|
|
#6
|
|||
|
|||
Re: Classes and allocating memoryQuote:
You can allocate memory with new in a class constructor (or other methods) just as usual. In addition, though, if you want to do it properly, you need to 1. provide a destructor for deleting the allocated memory. Pair operator new with delete and new [] with delete []. 2. Provide a copy constructor. This is also provided automatically if a class needs one. However, the automatic version does member-wise copying; it copies the addresses of pointers, which leads to memory problems when destructors are called (Destructors try to free the same memory multiple times). You need to provide a copy constructor that copies the data the pointers point to. 3. Overload the = operator. Reason same as above. There may be other pointers I forgot. (Hehhe, get that? other pointers?) |
|
#7
|
|||
|
|||
Re: Classes and allocating memoryok, here is new ,hopefully better looking code. I have it partially doing what it is supposed to do...
CPP / C++ / C Code:
if i create the deck , DECK PlayingCards(2); , it will let me define the two cards and when i have the program display all the variables from the two cards, it does just fine. The problem comes after that, when i get an "unhandled win32 app error"(generated by visual studio). I can fix this problem by changing, cards = new CARD[NC]; to cards = new CARD[NC * 10];. But that means i'm allocating far more memory than needed. here is a test program i used. CPP / C++ / C Code:
the result is... Press any key to continue . . . val: 1 color: g val: 2 color: g Press any key to continue . . . -- the error occurs here -- can someone help me? |
|
#8
|
|||
|
|||
Re: Classes and allocating memory1. provide a destructor for deleting the allocated memory. Pair operator new with delete and new [] with delete [].
Which you didn't do. Though I don't know if that's the cause of the error. Oh and really, don't use the system("PAUSE"). http://www.gidnetwork.com/b-43.html As mentioned in this forum, too, many times, an often simple and powerful debugging method is to put cout (that's right, cout since this is C++, not C) statements in strategic spots. Such strategic spots in this case could be the class destructors for example. Try it out. Last edited by Kimmo : 23-Jul-2007 at 04:49.
|
|
#9
|
|||
|
|||
Re: Classes and allocating memoryQuote:
Valiant effort, not quite there...for sure. Here are some points to consider: 1: Conventions: Your class naming convention is non-standard, at least. Usually we don't name classes in all uppercase letters. All uppercases are typically reserved for constants. This is strictly a convention, so you're free to march to the beat of a different drum if it so moves you, though I'd recommend sticking with conventions unless/until you develop a supporting case for going against them. 2: Integer data members as pointers: Unless you have a strong reason for using pointers, avoid them. They are powerful instruments, but along with power they bring more responsibility and require more management. In the case where you use a pointer to point to a single integer value, you're bringing more complexity to a simpler problem where a single int value (rather than int pointer) will handily solve the problem. 3: Default initialization versus allocation You're allocating memory for your pointers in your default ctor of CARD, but you're not allocating memory for your default ctor of DECK for your "cards" member. This is an explosion waiting to happen. Also, in CARD, you allocate memory, but you do not initialize the value pointed to by your pointer to some known good value. This is why pointers are more work. You must allocate memory for them and you must initialize them. An uninitialized pointer is a timebomb in your code. It is only a matter of time before it blows up. Also, if you have pointer members, you MUST have a cctor. 4: Variable naming convention: Your variable names are rather unconventional. I'd recommend that you find an existing convention that you can live with and use it until you better develop your skills to the point where you can assert your own convention. My recommendation is that you: A: Use title case for classes (eg) DeckOfCards Card B: Use camelback for operations (eg) setValue( ... ) getValue( ... ) C: Use the m_ prefix for your class member attributes (eg) m_value m_symbol D: Avoid meaningless names used in interfaces (eg) void BF_setotherc( char oc) ...other "c," what's a "c" supposed to be? Color, char? Something else? Avoid ambiguity. In your other interfaces, such as: void BF_setothern( int on) ...here, "setothern" and "on" are competing for recognition. When we look at the "on" it is an English word that means on versus off, are we turning other "n" on or off? No, we're setting "on" to some integer value because on means other "n." Here is a good point. If you can't come up with a better name than "other n" or "other c" then you haven't expressed your class design well enough to warrant these in your code. Come up with the correct name before you code it. If you can't come up with the exact right name, chances are you don't yet "need" it in your code. If for whatever reason you just know that you need it, then you should be able to come up with at least the reason why you need it and then the proper name for it based on what it is or how you're using it. The bottom line is that if you can't name it properly, it isn't ready to be in your code. E: What is with BF_ for your operation names? If BF_ means "Blue Fire," you really need to rethink your interface names in your classes. The name of the interface should be appropriate for the class that you're implementing. What is "natural" for the way that it is or should be used? And now, for something "good" about your design: You are apparently trying to utilize an appropriate level of abstraction in your CARD class. You are trying to make it so that CARD is a suitable CARD for everywhere that a CARD may be needed...at least in terms of gaming and not necessarily in terms of when a CARD might be a greeting card or a note card or some other kind of CARD that isn't meant to be part of a game of some sort. Actually, your CARD is simply a card that must have a value, a color and othern and otherc, etc. So, wherever that applies, your CARD is useful. Otherwise, it is decidedly not a CARD and therefore is a bad class design. If you refer back to my class design (not that it is something of beauty), you'll see that I named it PlayingCard. Also, I didn't define a base class of type Card from which PlayingCard would derive. In other words, I felt that "Card" was too broad of a topic to implement. However, it is very reasonable that one certainly could be implemented as a base class (probably as an ABC), but in my particular case, I felt that the value gained wasn't worth the cost. Would Card (the base) be a 2D or 3D object? Do we require it to be a rectangular object or just a 4 sided polygon? Is Card actually a Rectangle derived class, or is it derived from FourSidedPolygon? Is FourSidedPolygon and Rectangle both types of Polygons which is some kind of TwoD class which is some kind of Shape class? Since I didn't want to define the world according to Card geometery, I decided that I'd just make a base class of type PlayingCard such that it would represent a playing card and nothing more and (hopefully) nothing less. With regard to your CARD class, and this is a tough point to make to all ranges of programmers, you really want CARD to be nothing more and nothing less than what is exactly a CARD in every case where a CARD is useful or would be considered to be appropriate for use. In your case, your CARD class will not substitute for usefulness in the case where a CARD instance is not a kind of gaming card, but is a kind of greeting card. There is no "message," for example. There is no way of representing multiple "folds" of a greeting card, for example. In every situation, your class must fit the test of an "IS A" relationship. The bottom line is that your class is simply misnamed. It doesn't fit--nor was it intended to fit--all of the possible kinds of real-world CARDs that we can think of that meet the general name of "CARD." We already know that the compiler will let you call your class just about anything. It will also happily let you define your interfaces with names that may very well approach the absurd. Here is an exaggerated example: CPP / C++ / C Code:
...these things are not readily associated with what is or what a Feather does. Now, perhaps we can talk a bit about why your code is failing. The first thing to note is that whenever we break conventions, we open the door to more opportunities for failure. That is, if we stray too far from "the path," we encounter a greater likelihood of getting caught in a thicket. First, you'll never run into a shortage of people here who are willing to tell you that printf (or cout) are invaluable debugging tools. However, there seem to be no others here who would recommend using a symbolic debugger as a means of finding where in your code it breaks down. If the debugger is not your first tool for debugging your code, you'll always be a novice programmer no matter how great you think you are. Debuggers were especially developed for the purpose of debugging code. Neither printf nor cout were specifically designed as debugging tools. Both are little better than MessageBox when it comes to debugging code. I strongly recommend that you become intimately acquainted with your debugger and leave printf/cout to the novices. ...and, for the record, anyone who tells you that cout is somehow preferred over printf because this is, afterall, C++ code and not C code is disturbingly absurd. Granted, if you want to do things the C++ specific way, then, yes, cout should be your first choice, and is safer to use than printf. But, if you're using either as your front-line debugging tool, you've got bigger problems than how truly "C++" you are.... Quote:
I don't believe you! Hopefully you'll find that it can't possibly "do" what is is supposed to do until it "IS" what it is "supposed" to be. Refer to my Feather shown previously. If it really IS a "FeatherDuster" then it can't possibly be "correct" if we call it a RangeRover. Granted, my choices of names in this context are completely ridiculous, hopefully you'll see that they are exaggerated to make the point. No matter how finely inappropriately named a class "is," it breaks down the IS A relationship. Therefore, no matter how absurdly WRONG a class name is, it still can't be the RIGHT "IS A" relationship. I stand behind my statement that the single most difficult thing about OO programming is proper naming. 'Tis but thy name that is my enemy;-- Thou art thyself, though not a Montague. What's Montague? It is nor hand, nor foot, Nor arm, nor face, nor any other part Belonging to a man. O, be some other name! What's in a name? that which we call a rose By any other name would smell as sweet; --Juliet, Romeo and Juliet, Act II, Scene 2, William Shakespeare ~1595. Quote:
I haven't actually analyzed your code, but this suggests to me that you are reading past the end of an array and that somehow, by allocating more memory, you are not wandering into the weeds as badly as you are otherwise. You can't really "fix" this without going back to the basics and ensure that every single pointer is always allocated and initialized to some known good value. DECK is not a "deck" if we're talking about the back porch. Again, naming challenges crop up. I want to try to tell you how to fix your code, but really it needs to be rewritten with more attention to following standard conventions for naming of attributes and operations and the various bullet points I mentioned previously. I don't mean to say this in order to get you to do more work than is necessary, rather, hopefully you'll figure out what work IS necessary and nothing more. There is enough work already in C++. There is not a very robust class library such is the case with Java and other API. However, we can not shirk responsibility when it comes to writing C++ code. Here are some points to remember: A ctor initializes the object to a known good state. The default ctor MUST put the class into a known good state. While there are those who will argue that the ctor should throw an error on failure, it is my contention that a ctor NEVER FAILS. In other words, if it can't succeed (for any reason other than lack of system resources), then you haven't properly coded it. The recommendation in such cases is to move complex initialization out of the ctor and use try/catch in the ctor to handle cases where initialization may fail such that the ctor can recover. In cases where an external dependency is required, such as a database connection, the ctor should still succeed but operations should THROW an error. This, of course, assumes that you are using exception handling as a means of propagating faults. Better is to ensure that there are no faults. Granted, it is often a lot easier to code to fail on fault, so you may elect to do what pleases you or those for whom you write your code. I've gone on far too long in this response. If you decide to rewrite your code, I'll continue to critique it. Alternatively, this junk is yours, you own it, you fix it. This is not meant to be rude, but it is certainly rudimentary. Try to remember that what is NOT in the code is nearly as important as what IS in the code. Please strongly consider using the "is this really, absolutely IS A" whatever you name a class, variable or operation. This is a very strong "test" of whether or not something else "works" with the class design. If Feather doesn't really scale buildings, then we've got issues whenever someone tries to scale buildings with it. C++ gladly allows us to assert that feather is the master of building scalers whether it makes any rational sense or not. In other words, C++ has no sense at all. It depends entirely upon us to provide it with sense and that sense comes from properly naming those user defined types that are found in our code. :davis: Last edited by admin : 24-Jul-2007 at 11:16.
Reason: fixed typo in bbcode tag
|
|
#10
|
|||
|
|||
Re: Classes and allocating memoryQuote:
I want to recommend that you completely STOP recommending cout/printf as a means of debugging. Not only is it NOT "powerful," it is a poor choice for real debugging. For example, when was the last time that printf/cout found the uninitialized pointer? What happened? Did someone printf/cout "got here" only to find that it didn't get there? If you regularly rely on printf/cout as a debugging tool, you are a total wannabe novice. You should be using your debugger. There are cases where printf/cout are useful, such as in text parsing but this is certainly NOT the case in this code. If you continually recommend printf/cout, you are needlessly continuing the myth that printf/cout are proper debugging tools. They ARE NOT! If you rely heavily on them, then you are truly a wannabe programmer. This is not meant to be rude. This is not meant to be an insult. Please feel free to somehow justify printf/cout as a "debugging tool," compared to using a "real" debugger. Expand upon your reasoning in someway that somehow brings light to how printf/cout is truly the debugging friend that you imply. printf/cout litters your code with BAD code that isn't meant for the intended use of the code. What are you going to do, write more and more throw-away code every day? Wow. Productivity at peak. Gotta love THAT! :davis: |
Recent GIDBlog
Problems with the Navy (Chiefs) by crystalattice
| Thread Tools | Search this Thread |
| Rate This Thread | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Memory Block Size | wayne--scales | C Programming Language | 6 | 24-Apr-2007 15:50 |
| Beginner working with classes | Timothy_Bennett | C++ Forum | 14 | 05-Apr-2007 23:22 |
| Dynamic memory allocation of unknown/variable data length | Radi0ShacK | C++ Forum | 18 | 14-Feb-2006 22:26 |
Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The