Quote:Original post by Domarius
Yeah I did make a typedef :) ... our instructor (back when I used to study) did this so I have just been following suit, everything he does, till I know better.
Consider questioning things openly. Acceptance is not learning. If something is justified, then your instructor should be able to state the justification.
The typedef here might be to allow for changing the underlying type later - I can indeed imagine that happening in at least one way (to std::wstring, for Unicode "support" - and I use the term loosely). It might be to avoid typing std:: everywhere, but there's a better way to do that (a using-declaration: 'using std::string;'). Or it might just be because your instructor thinks the uppercase name looks better. Whatever the case, it's worth finding out what the reasoning actually was.
Quote:
Oh... I am just in the habit of cleaning up everything... if I delete all variables then I want to close all files too... is it bad practice?
In C++, objects are supposed to be designed to clean up their own messes. When you dynamically allocate something, you need to 'delete' it (or 'delete[]' for an array allocation - the two are NOT interchangable), yes; but the way to do things is *not* to try to figure out everywhere the object needs to be cleaned up and insert the call, but instead arrange for it to happen *automatically*, using destructors. That's what they're in the language for.
In the case of iostreams, the destructor simply calls .close() (or has the same effect). The net result is that you don't have to worry about putting in the call at every point where the stream could go out of existence. Because of exceptions, there are actually a LOT more of these than you think. It's inconsistent to handle the "normal" ones explicitly and forget about exception situations; so it makes more sense to not handle anything explicitly at all - why do extra work that accomplishes nothing?
Done properly, we accomplish a very powerful idiom called RAII - Resource Acquisition Is Initialization - a misnomer, because the idiom is usually seen as much more about the cleanup than it is about the setup (which is "obvious"). Example. (As you can tell from my sig, I'm quite fond of this particular example ;) ) What's going on is that, because the string's destructor deallocates the memory, we don't have to and shouldn't think about that task. It's not the responsibility of our code.
Quote:
But I have a very specific format of CSV for this app I'm making (my app cannot make use of any other format - must have string, string, int, int for each row), and while it would be more reliable to use that CSV thing I downloaded, I wouldn't be learning much, except how to use someone elses class.
If it's your file format, don't feel compelled to emulate CSV in any way, shape or form. Use things that are easy to parse naturally in C++. Reading up until a specific character is easy (just specify that third argument for std::getline :) ), and reading ints that are separated by whitespace is easy. If possible, use a character to separate the strings that can't appear within them - you can choose what you like, after all.
If there is no such character, then you will need some sort of escaping system. You might want to consider how the C++ language itself does things in its syntax - that way is really robust (you can be sure that every possible string is representable), but it's hard to parse from within C++ (maddeningly enough). A simpler way is to treat a doubled-up separator as an escape code for the separator: after reading up to a separator, check if the next "item" is empty, and if it is, append the separator character and keep going. However, this way will not allow you to represent empty strings. But in general, try to avoid scanning the thing character by character; it's usually too much work. (Although it *is* pretty much required for the C++-syntax-style approach.)