|
Smackbilly has given a pretty thorough explanation, so I'll just try to give some supplementary info (although it's pretty late, so I may inadvertantly type up something that's not correct)quote:I had the operator [] overloaded to help with the comparison, but that doesn't work now, which I'm assuming is causing the error. code:
If I have understood your problem description correctly, it also seems to me that your code could be greatly simplified. Since you want to step through the vector of existing rows and insert the current row before any element that is lexicographically greater than it is (i.e you have an existing vector [A, C, F] and you're inserting D, you reach a point where you see that D < F), you can break off your loop at that point and insert the row. Conveniently, vector::insert inserts the given element before the element the iterator points to, which is exactly what we want assuming: rows is an instance of vector<vector<string>*>, and row is an instance of vector<string>* allocated on the heap per iteration: code:
edit: to clarify, the code assumes that a new instance of row is created for each loop iteration, since the rows-vector naturally must be filled with distinct objects to work The Red Baron fucked around with this message at 05:35 on Oct 12, 2008 |
# ? Oct 12, 2008 03:48 |
|
|
# ? Jun 8, 2024 13:25 |
|
Thanks a ton for going into more specifics! It's frustrating how difficult it is to find this kind of information in a clear, concise manner online, using non-complicated examples. I'm still a little confused about dereferencing, though - how does it know when to deallocate the memory? Does that have to be done in a destructor? While that really compact for-loop looks appealing, it won't run if it's empty - there's nothing in the table yet. The beginning is the end. I added a check to see if it was empty and made it into an if-else statement. But there's a problem. I added a lot of other code just to make sure the problem wasn't the method - it happens no matter which method I use, as long as it involves that specific for-loop and comparison. It seems that no matter what, (**tableItr) is always the first element of the row being inserted. It doesn't start at the beginning of the table. In fact, even though the iterator is told to increment, it doesn't move at all. At the beginning of every for-loop, (**tableItr) is the very first element of the current row. I've added some debug statements. code:
(the first element was Alan, but I did not include a cout statement in the "if empty" loop) *tableItr is 0xffffffff7ffff450 **tableItr before the for-loop is Bob Table size is 1 Row 0 is Bob **tableItr is Bob Table size is 2 *tableItr is 0xffffffff7ffff450 **tableItr before the for-loop is Charles Table size is 2 Row 0 is Charles **tableItr is Charles Table size is 3 *tableItr is 0xffffffff7ffff450 **tableItr before the for-loop is Clementine Table size is 3 Row 0 is Clementine **tableItr is Clementine Table size is 4 So obviously things aren't getting added in lexographical order because each row is being compared to its own first element instead of the first element of the nth row the table (twoDimStrVec). It never gets beyond that first if statement, because it's always true. Taking away the equal sign resulted in other errors, and does not solve the problem of (**tableItr)[0] always being of the current row. The second time through should be if (Bob <= Alan) Instead, it's if (Bob <= Bob) The iterator is not being incremented. I don't know what the hell it's doing. I found something here http://www.velocityreviews.com/forums/t456722-segmentation-fault-calling-insert-on-vector.html That suggests that "insert" returns some kind of iterator each time it's called - but how can that be fixed, and why am I not seeing a ton of other people having problems like this? I found another case with a similar problem, but it's a few years old and he never got an answer. http://www.daniweb.com/forums/thread34928.html
|
# ? Oct 12, 2008 08:29 |
|
Using pointers, the following is pretty commoncode:
code:
|
# ? Oct 12, 2008 09:50 |
|
code:
EDIT: Sorry if you understood that; late night snark is not helpful. Basically, no, there's no way to do what you want to do, at least not unless you can't rework it to use a ternary operator: the referent of a reference variable has to be fixed at the time of creation. rjmccall fucked around with this message at 10:18 on Oct 12, 2008 |
# ? Oct 12, 2008 10:02 |
|
quote:While that really compact for-loop looks appealing, it won't run if it's empty - there's nothing in the table yet. The beginning is the end. I added a check to see if it was empty and made it into an if-else statement. But there's a problem. I added a lot of other code just to make sure the problem wasn't the method - it happens no matter which method I use, as long as it involves that specific for-loop and comparison. Here's the problem: you're re-using the same vecRows object over and over again for each row, and you're storing a pointer to it in the table. When you insert a pointer to the vecRows object into the table, you are not copying the contents of the vecRows vector into the table; you are only pointing back to it. So if you insert a pointer to vecRows into table slot 0, that means that when you later retrieve the contents of table slot 0, it just follows the pointer and reads whatever is currently in the vecRows object that you have a pointer to. So when you insert a pointer to the vecRows object, and then you then overwrite the vecRows object's contents with the next row, dereferencing the pointer in the table will then get you the new data in vecRows (because remember no copy was ever made). In short: because the table contains a pointer to the row vector, changing the contents of the row vector changes the contents of the table. This problem is really easy to avoid in the following manner: don't use pointers. There is absolutely no reason for you to be using pointers here. When I saw the code snippet you posted earlier, I assumed that there was some good reason why twoDimStrVec was a vector of pointers-to-vectors rather than a vector of vectors. I looked back through the thread to your initial post, and there's no reason at all for that to be the case. Just do this and all will be well: code:
Almost all of your confusion here seems to be because you are really eager to use lots of pointers when they are not necessary. No part of this process that we are helping you debug requires the use of any pointers. I suggest that you do some further reading on pointers (even the Wikipedia article or something) to help yourself understand what pointers really do and when/why they are necessary.
|
# ? Oct 12, 2008 10:15 |
|
It needs to be a vector of pointers to vectors of strings, though - this file is massive. This hit the nail on the head as to why I need to do it:The Red Baron posted:Having the outer vector contain pointers to vectors of strings removes the potentially great overhead of copying every single inner vector and all their strings when the outer vector itself is copied (or resized). However, it requires you to either manually perform memory management to delete the inner vectors when they're no longer needed, use shared pointers rather than raw pointers or use a dedicated pointer container such as boost::ptr_vector.
|
# ? Oct 12, 2008 16:25 |
|
Whilst farting I posted:It needs to be a vector of pointers to vectors of strings, though - this file is massive. This hit the nail on the head as to why I need to do it: Well, first of all I'm not convinced that using pointers will really make your program go all that much faster. This program is executing a loop of the form 1. read some data from disk, 2. move some stuff around in memory. Disk I/O is exponentially slower than memory access, so 90%+ of your program's time is going to be spent on step (1) rather than step (2) and making step (2) faster won't help all that much. But if you insist on using pointers, what you have to do is make vecRows into a pointer, and allocate new memory for it each time you start reading a new row. Declare vecRows as type vector<string>*, and replace the vecRows.clear() line with vecRows = new vector<string>(). Then, update the rest of the method so that vecRows[0] becomes (*vecRows)[0] (dereference the pointer to get the vector it points to before using the [] operator) and &vecRows becomes vecRows (no longer need to take the address, since vecRows is now itself a pointer). Now since you are allocating a new vector every time you read a row, you are no longer overwriting the contents of the vector that you have already stored a pointer to in the table. The downside of this is that you now have to worry about manually releasing that memory when it is no longer used, or else you will have a memory leak in your program. At minimum, this means defining a destructor for your class and having it iterate through twoDimStrVec, and call "delete *tblItr" (assuming that's what you call the iterator again. If your class provides a method to remove rows from the table, then you will have to call delete on the row pointers when you remove them from the table as well.
|
# ? Oct 12, 2008 19:36 |
|
rjmccall posted:
Less than helpful, I'm afraid, because now I'm confused as to whether my example was unclear or whether the thing I'm actually trying to do is just crazy! I really appreciate the help though I'm thinking about the case where getFoo() and getBar() are member functions of something, returning const pointers (or const references) to existing objects. With a base class pointer, you get the derived class behaviour, with a base class reference you get a compile error. It seems like a hole in the language, to me - if you're going to make references use polymorphism, then they should be able to use the abstract base class functionality as well, as I see it? If it is a hole in the language that's understandable - I'm not insisting that the language is perfect - I'm just wondering if there's a design rationale behind this that I'm missing. As I said, thanks heaps for the comments - they're most helpful.
|
# ? Oct 13, 2008 00:11 |
|
awesmoe posted:It seems like a hole in the language, to me - if you're going to make references use polymorphism, then they should be able to use the abstract base class functionality as well, as I see it? No it isn't. You just can't change what a reference points to after you declare it. Think of it like a Foo * const. Besides, you can still do code:
|
# ? Oct 13, 2008 00:35 |
|
I'm just starting to learn C++, my first computer language, and I've decided to test what I've learned by making a simple program that converts between Fahrenheit and Celsius. I'm using a switch case statement, and a user types 1 or 2 to choose either Fahrenheit or Celsius. Everything works fine there. But if they accidentally choose some other number, the program just shuts down. Isn't cin.get() supposed to prevent this, forcing the program, with the error message I included, to stay visible until the user hits enter? Here's my program: code:
|
# ? Oct 13, 2008 01:29 |
|
Smackbilly posted:Well, first of all I'm not convinced that using pointers will really make your program go all that much faster. This program is executing a loop of the form 1. read some data from disk, 2. move some stuff around in memory. Disk I/O is exponentially slower than memory access, so 90%+ of your program's time is going to be spent on step (1) rather than step (2) and making step (2) faster won't help all that much. Obviously it won't run lightning quick, but isn't it faster to run it and output elements by passing the address of the element to be printed rather than passing the entire element itself? quote:But if you insist on using pointers, what you have to do is make vecRows into a pointer, and allocate new memory for it each time you start reading a new row. Declare vecRows as type vector<string>*, and replace the vecRows.clear() line with vecRows = new vector<string>(). I knew it had something to do with declaring a new vector every time through the loop - I tried setting vecRows = new vector<string> but the compiler didn't like that. I knew I had to make vecRows into a pointer, too - but again, the syntax (and a bit of the logic) escaped me. quote:The downside of this is that you now have to worry about manually releasing that memory when it is no longer used, or else you will have a memory leak in your program. At minimum, this means defining a destructor for your class and having it iterate through twoDimStrVec, and call "delete *tblItr" (assuming that's what you call the iterator again. If your class provides a method to remove rows from the table, then you will have to call delete on the row pointers when you remove them from the table as well. "delete *tblItr" releases the memory location at *tableItr but the memory location will still have the elements in them, if I'm understanding this correctly? Like if 0x10010b2b0 holds "Alan", if I don't release that memory by the time the program is finished executing, no other program will be able to use that memory and it will still hold "Alan." However, if I do release the memory, other programs will be able to use 0x10010b2b0, but it will still hold "Alan" but other programs will just overwrite it. If this is the case, how bad is it to not delete the row pointers and where exactly do they fit in?
|
# ? Oct 13, 2008 03:15 |
|
Whilst farting I posted:Obviously it won't run lightning quick, but isn't it faster to run it and output elements by passing the address of the element to be printed rather than passing the entire element itself? quote:"delete *tblItr" releases the memory location at *tableItr but the memory location will still have the elements in them, if I'm understanding this correctly? quote:Like if 0x10010b2b0 holds "Alan", if I don't release that memory by the time the program is finished executing, no other program will be able to use that memory and it will still hold "Alan." However, if I do release the memory, other programs will be able to use 0x10010b2b0, but it will still hold "Alan" but other programs will just overwrite it. I doubt this will be a showstopper-problem with your current application unless the datasets you process are truly immense or you're running it over and over again for a long time without exiting it, but getting a good practice down as soon as possible when it comes to memory management is a Good Thing(tm). The thing with C++ is that despite what many people believe, getting memory management right is pretty straight forward. Learn how std::auto_ptr and boost::shared_ptr work, what their application areas and limitations are (the latter in particular for auto_ptr), understand how scopes work, and read up on RAII (Resource Acquisition is Initialization). These are pretty much crucial to writing code that won't poo poo itself when exceptions start entering the picture, and will also make writing code much more enjoyable
|
# ? Oct 13, 2008 04:29 |
|
Gary2863 posted:Isn't cin.get() supposed to prevent this, forcing the program, with the error message I included, to stay visible until the user hits enter? I guess you ought to put cin.get() before break. Otherwise that line is unreachable and never gets executed.
|
# ? Oct 13, 2008 06:08 |
|
Gary2863 posted:words Shouldn't you clear the input buffer before you try to use cin.get / ignore? Also, you're not returning anything.
|
# ? Oct 13, 2008 09:04 |
|
Web Service returning DataSet to Web Page Okay, I have a WebService I've written providing return DataSet's to another programmer who is designing an aspx webpage using the GridView to display the returned data. On Page Load he is doing a Bind() to the returned DataSet and displaying the results in his Grid. This works fine. What he is wanting to do at this point, is click a link over any of the columns in the Gridview and sort/resort the Data which he bound to the grid. I figured the DataSet still exists in memory or somewhere and he shouldn't have a problem manipulating from another event on the Grid. But he says this won't work. Any reason why returned datasets can't be manipulated after they've been loaded into a page? If there is a way to do this - is the fix on my end or his? Anyone have any ideas?
|
# ? Oct 13, 2008 22:15 |
|
I think you might want the .NET thread, http://forums.somethingawful.com/showthread.php?threadid=2262300
|
# ? Oct 13, 2008 22:31 |
|
magicalblender posted:I guess you ought to put cin.get() before break. Otherwise that line is unreachable and never gets executed. You got it, this fixed it. Thanks! slovach posted:Shouldn't you clear the input buffer before you try to use cin.get / ignore? I'm very new at this, I made the temperature converter on my first day of working with C++. I read somewhere that programs return a 0 to the operating system if they run successfully, but I wasn't sure what the importance of that was. Is that what you're talking about? Also, I don't know how to clear the input buffer yet. The program seems to do its job perfectly now even if it's not the way it should be coded. Still, I appreciate any clear advice about it, just please be aware I am at the very beginning of the learning process here.
|
# ? Oct 13, 2008 22:40 |
|
Gary2863 posted:I'm just starting to learn C++, my first computer language, and I've decided to test what I've learned by making a simple program that converts between Fahrenheit and Celsius. I'm using a switch case statement, and a user types 1 or 2 to choose either Fahrenheit or Celsius. Everything works fine there. But if they accidentally choose some other number, the program just shuts down. Isn't cin.get() supposed to prevent this, forcing the program, with the error message I included, to stay visible until the user hits enter? You can also use your OS to pause, clear the screen and other fun stuff. code:
code:
code:
[/book]
|
# ? Oct 13, 2008 22:51 |
|
The Lost posted:the system command can issue any OS command line call you want to make. Great for pausing and clearing screen. Generally speaking, this is inadvisable. Besides being non-portable (obviously), it places a lot of assumptions on how your application is being used. It's better to avoid system calls wherever possible; rather than using a system call to pause, it's better to just open a command prompt and run from there. Or, if you really need all kinds of whiz-bang stuff to mess with the console, use something like ncurses.
|
# ? Oct 13, 2008 23:28 |
|
So, hopefully really simple question: I'm used to Java, and I'm trying to pass a single character into a vector<string>, which apparently isn't just automatically cast up. Do I actually have to do something ridiculous like: code:
|
# ? Oct 13, 2008 23:50 |
|
temp += c_string[i] Edit: Or that VVV (that's what I get for skimming) Avenging Dentist fucked around with this message at 00:00 on Oct 14, 2008 |
# ? Oct 13, 2008 23:56 |
|
electric_vaseline posted:So, hopefully really simple question: char c = 'a'; std::vector<std::string> myvector; myvector.push_back (std::string (1, c)); TOO SCSI FOR MY CAT fucked around with this message at 00:01 on Oct 14, 2008 |
# ? Oct 13, 2008 23:57 |
|
The Red Baron posted:If by outputting you mean using "std::cout << whatever", it uses references anyway, which means it'll never be copying the entire element just to print it. The dataset is indeed truly immense - it's several thousand lines long. I've never heard of RAII or the other things you mentioned, I'm looking into that now. Basically I had a very vague idea about all this and you snapped it all into place. This has been truly enlightening, especially about pointers and memory leaks and deallocation - thank you to all who helped me. I'd offer gift certs for being so clear and helping me to gain an understanding of what the hell I'm doing, but I'm flat-broke. I learned way more from your posts than I did from several different C++ books I consulted and anything I could find online. Thanks again for the detail and clarity! Whilst farting I fucked around with this message at 00:48 on Oct 14, 2008 |
# ? Oct 14, 2008 00:46 |
|
Janin posted:char c = 'a'; Avenging Dentist posted:temp += c_string[i] It did help though with another problem I was having with using append as I didn't think += would work in C++, so thanks! (Btw, VVV?)
|
# ? Oct 14, 2008 00:52 |
|
electric_vaseline posted:(Btw, VVV?) ^^^ and VVV are used to indicate other posts.
|
# ? Oct 14, 2008 01:02 |
|
Janin posted:^^^ and VVV are used to indicate other posts. Ah! Of course. Well, new question. I keep getting this error message and I've been pounding my head for hours trying to figure it out but I can't. The error: quote:1>Tester.obj : error LNK2019: unresolved external symbol "public: static class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl Utility::Join(class std::vector<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::allocator<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > >,char)" (?Join@Utility@@SA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$vector@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$allocator@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@2@@3@D@Z) referenced in function _main The offending code: code:
code:
|
# ? Oct 14, 2008 02:12 |
|
The linker is saying it can't find Utility::Void. If the Void method is defined in the class Utility, you need to declare that as part of the method signature:code:
|
# ? Oct 14, 2008 02:16 |
|
csammis posted:The linker is saying it can't find Utility::Void. If the Void method is defined in the class Utility, you need to declare that as part of the method signature: Oh! Crap! Of course! Hahaha, I can't believe I forgot the Utility::
|
# ? Oct 14, 2008 02:22 |
|
Also, please change const vector<string> vInput to const vector<string>& vInput You really don't want to be passing vectors around by value
|
# ? Oct 14, 2008 02:28 |
|
Avenging Dentist posted:Generally speaking, this is inadvisable. Besides being non-portable (obviously), it places a lot of assumptions on how your application is being used. It's better to avoid system calls wherever possible; rather than using a system call to pause, it's better to just open a command prompt and run from there. Or, if you really need all kinds of whiz-bang stuff to mess with the console, use something like ncurses. ncurses is problematic because its a non-standard library, so a beginner would then have to either install extra libaries and/or know how to set up your linker to use non-system libraries. So unless your constrained to a system w/o any graphics libraries/capabilities you might as well start looking a some form of graphical programming. Or start using Java if your field permits. System is non-portable, but is standard C/C++. If your seriously worried about portability then you can set up pre-compiler directives to set a proper value to a c-string #define and use that in place of the string literal "cls" or whatever. System is a nice easy cheese console function that doesn't require any serious back ground. Its great for playing around with console apps when your just starting out. Use it or don't. Its just a thought.
|
# ? Oct 14, 2008 02:55 |
|
Whilst farting I posted:The dataset is indeed truly immense - it's several thousand lines long. Since when was several thousand lines an "immense" dataset?
|
# ? Oct 14, 2008 04:05 |
|
The Lost posted:No, my main point was that using system calls puts a lot of assumptions on your console app and 99% of them are unnecessary. system("pause") is my least favorite since people always use it as a workaround for the fact that Windows closes command prompts on termination when you double-click on the exe. Just open a command prompt first, or just use Visual Studio which will leave the command prompt open anyway. And if you're not using Visual Studio on Windows, you're honestly kinda dumb.
|
# ? Oct 14, 2008 04:09 |
|
Avenging Dentist posted:just use Visual Studio which will leave the command prompt open anyway. only if you run the program without debugging. If you start it using the debugger, it'll close on exit. It's unfortunate but true
|
# ? Oct 14, 2008 04:26 |
|
Breakpoints
|
# ? Oct 14, 2008 04:37 |
|
How about just cin.get(), getc()... ?
|
# ? Oct 14, 2008 06:27 |
|
I think pretty much anything trying to force a pause in a console app is kinda dumb. If you're just learning how to program, you shouldn't really be worried about usability, just about learning the concepts. If you're an experienced programmer writing a console app, you should be using command line arguments anyway. I mean, at the end of the day, do whatever you want, but I think stuff like that is kinda hacky, and really a lot less useful than people make it out to be.
|
# ? Oct 14, 2008 06:40 |
|
I'm a C# web application programmer by day, but I've been brushing up on my C/C++ skills by going back through K&R and Accelerated C++. I've been working on a few games off and on but not a whole lot of other projects in C/C++. What are some other good projects to work on that would be an advantage for the language? I've thought about learning some embedded programming but barely know where to start. Any recommendations? (Guess I'm just looking to write programs that are closer to the metal. Of course, nothing too complicated right now. I'm not going to be writing an OS kernel yet.)
|
# ? Oct 14, 2008 13:27 |
|
Avenging Dentist posted:I think pretty much anything trying to force a pause in a console app is kinda dumb. If you're just learning how to program, you shouldn't really be worried about usability, just about learning the concepts. If you're an experienced programmer writing a console app, you should be using command line arguments anyway. I mean, at the end of the day, do whatever you want, but I think stuff like that is kinda hacky, and really a lot less useful than people make it out to be. The program you’re going to write will read 10 names from a file. Then print a menu. The user can select to search for a name, print all the names or exit. If the user chooses to search for a name clear the screen, prompt for the name, then search the list of 10 names. If the name is found print the number of the record in the list of names. If not print an error message. In either case pause for user input before clearing the screen and returning to the menu. If the user chooses to print all the names, print the record number then the name. Pause for user input and then clear the screen and return to the menu. If the user chooses to exit, clear the screen and print a termination message. This is the type of program I typically run for a second semester programming class to review arrays and introduce searching/sorting. Sure I could make it less interactive. Hell you could read all the user input from a file. However capturing student interest and providing them with the opportunity to do something that feels closer to the types of programs they want to write is an essential tool in teaching. It helps to get the students to think in the direction we want while allowing them to do something that interests them. The hope of course is that as they work on the guts of the assignment they become more interested in the mechanics than the show. Of course if you’re not worried about teaching people how to program and are focused on actual console projects then yeah, no real point in pausing, clearing the screen or anything else.
|
# ? Oct 14, 2008 17:38 |
|
Avenging Dentist posted:I think pretty much anything trying to force a pause in a console app is kinda dumb. If you're just learning how to program, you shouldn't really be worried about usability, just about learning the concepts. If you're an experienced programmer writing a console app, you should be using command line arguments anyway. I mean, at the end of the day, do whatever you want, but I think stuff like that is kinda hacky, and really a lot less useful than people make it out to be. Hard to learn the concepts if you can't see what your program is outputting though. While there are other ways around this, grabbing a character from input is fine if you want to just hit F5 in VS. Worrying about details like breakpoints when you're writing your first application is just silly. I wasn't really paying attention to the thread, I see he already was using cin.get(). I agree that system("pause") is a horrible thing to do.
|
# ? Oct 14, 2008 17:45 |
|
|
# ? Jun 8, 2024 13:25 |
|
cronio posted:Hard to learn the concepts if you can't see what your program is outputting though. While there are other ways around this, grabbing a character from input is fine if you want to just hit F5 in VS. Worrying about details like breakpoints when you're writing your first application is just silly. I don't see why you'd run in debug mode unless you have breakpoints set. Running without debug (Ctrl+F5) will keep the command prompt open, and if you compiled in debug mode, the JIT debugger will load up if something goes haywire anyway.
|
# ? Oct 14, 2008 17:49 |