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
Dooey
Jun 30, 2009
I'm not exactly a C++ Guru so someone please correct me if I'm wrong, but it all depends on the underlying implementation of the container.

For example, when you add something to the front of a vector, the whole vector may need to be reallocated, which would cause any iterators to become invalid. But a list doesn't need to move any data about except for the data you are adding and removing from the list, so resizing it doesn't invalidate iterators. (Unless you remove the item your iterator is at)

So no, there are no hard-and-fast rules on when your iterators become invalid. Or maybe I'm wrong, I am naught but an undergrad student after all.

Adbot
ADBOT LOVES YOU

Painless
Jan 9, 2005

Turn ons: frogs, small mammals, piles of compost
Turn offs: large birds, pitchforks
See you at the beach!
The STL programmer's guide does, in fact, contain hard-and-fast rules for when STL container iterators become invalidated. Of course, you're probably not actually using STL, but I don't think the rules are any different between standard library containers and their STL counterparts.

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.

Ledneh posted:

Running into a goofy bug with a find() call on a map causing a segfault and it's really aggravating, I'm kind of flailing hoping I have a screwed up iterator somewhere at this point :smith:
Are you using std::find() or the map's find() member function? If std::find(), unless you created the iterators, then modified the map, then called find (or are modifying it in another thread while calling find), the iterators will be valid. If you're using the member function, the only thing that would break that would be another thread modifying the map.

How about a code snippet?

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Mustach posted:

Are you using std::find() or the map's find() member function? If std::find(), unless you created the iterators, then modified the map, then called find (or are modifying it in another thread while calling find), the iterators will be valid. If you're using the member function, the only thing that would break that would be another thread modifying the map.

How about a code snippet?

The member function, and the app in question is single-threaded. We're utterly baffled. (I don't think I've ever actually used std::find(), now that I think about it.)

Oh well, fresh eyes this morning, maybe we'll have better luck.

And thanks for the link to the programmer's guide, I'll poke through that. :)

(edit) As for a code snippet, maybe after I get to work, after I've taken another look.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
I never really dealt with the iterator rules before but while learning a lot more about the various containers that are available in STL, I found that those SGI documents for each container will mention something about it/how it blows up iterators. I guess that doesn't help though since you were looking for general rules of some kind.

I'm going to dig up IDEs (minimally) (again). I'm trying to make something that's getting to be complicated enough that I would benefit from autocompletion for methods and class members generally, and making something that could take a good shot at finding and opening the code where something is declared for me. I am currently playing the grep game and opening a ton of emacs buffers to try to figure out just names of things and their prototypes. I could stick with emacs, but preferably if it has some solution to this kind of thing.

BigRedDot
Mar 6, 2008

Dooey posted:

I'm not exactly a C++ Guru so someone please correct me if I'm wrong, but it all depends on the underlying implementation of the container.
Which container operations invalidate iterators and under what circumstances is stipulated precisely in chapter 23 of the C++ standard. (Talking about C++98, of course.)

Here is an example:


code:
23.2.2.3 list modifiers [lib.list.modifiers]
iterator insert(iterator position, const T& x);
void insert(iterator position, size_type n, const T& x);
template <class InputIterator>
void insert(iterator position, InputIterator first,
InputIterator last);
void push_front(const T& x);
void push_back(const T& x);
1 Notes: Does not affect the validity of iterators and references. If an exception is thrown there are no
effects.
2 Complexity: Insertion of a single element into a list takes constant time and exactly one call to the copy
constructor of T. Insertion of multiple elements into a list is linear in the number of elements inserted,
and the number of calls to the copy constructor of T is exactly equal to the number of elements inserted.
iterator erase(iterator position);
iterator erase(iterator first, iterator last);
void pop_front();
void pop_back();
void clear();
3 Effects: Invalidates only the iterators and references to the erased elements.
4 Throws: Nothing.
5 Complexity: Erasing a single element is a constant time operation with a single call to the destructor of T.
Erasing a range in a list is linear time in the size of the range and the number of calls to the destructor of
type T is exactly equal to the size of the range.

BigRedDot fucked around with this message at 19:14 on Jul 30, 2010

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.

Rocko Bonaparte posted:

I'm going to dig up IDEs (minimally) (again). I'm trying to make something that's getting to be complicated enough that I would benefit from autocompletion for methods and class members generally, and making something that could take a good shot at finding and opening the code where something is declared for me.
Eclipse's C/C++ plugin is pretty good at these things (auto-complete when you type '.', '(', or ',', and Ctrl + left click to open declaration or definition), with the typical downsides that come with Eclipse (buggy, can become unresponsive or outright hang, etc.). There are also plugins that advertise emacs keybindings, but I've never used any of them.

Dooey
Jun 30, 2009

BigRedDot posted:

Which container operations invalidate iterators and under what circumstances is stipulated precisely in chapter 23 of the C++ standard. (Talking about C++98, of course.)

Here is an example:


code:
23.2.2.3 list modifiers [lib.list.modifiers]
iterator insert(iterator position, const T& x);
void insert(iterator position, size_type n, const T& x);
template <class InputIterator>
void insert(iterator position, InputIterator first,
InputIterator last);
void push_front(const T& x);
void push_back(const T& x);
1 Notes: Does not affect the validity of iterators and references. If an exception is thrown there are no
effects.
2 Complexity: Insertion of a single element into a list takes constant time and exactly one call to the copy
constructor of T. Insertion of multiple elements into a list is linear in the number of elements inserted,
and the number of calls to the copy constructor of T is exactly equal to the number of elements inserted.
iterator erase(iterator position);
iterator erase(iterator first, iterator last);
void pop_front();
void pop_back();
void clear();
3 Effects: Invalidates only the iterators and references to the erased elements.
4 Throws: Nothing.
5 Complexity: Erasing a single element is a constant time operation with a single call to the destructor of T.
Erasing a range in a list is linear time in the size of the range and the number of calls to the destructor of
type T is exactly equal to the size of the range.

Maybe I misinterpreted his question, but I thought he was looking for something more general, like: Inserting into any container will invalidate iterators, removing from any container wont, resizing any container wont, etc.

BigRedDot
Mar 6, 2008

Dooey posted:

Maybe I misinterpreted his question, but I thought he was looking for something more general, like: Inserting into any container will invalidate iterators, removing from any container wont, resizing any container wont, etc.

I edited to add something like that but you are too fast. :) Here's the best "rule of thumb" I have: AFAIK associative container iterators are the most robust, retaining valid iterators after insert operations, and only invalidating iterators to specifically erased elements. List iterators are also fairly robust in the same way although some operations like spice(...) will still invalidate list iterators. vector and deque iterators are the most fragile and are invalidated under pretty much any insertion or erasure.

Edit: though tbh I do think looking up the actual concrete answer is better than rules of thumb. :)

BigRedDot fucked around with this message at 19:20 on Jul 30, 2010

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Yeah I was looking for a general answer, though when I say that keep in mind that at the time I wasn't aware the volatility of different containers' iterators could be so variable.

At least now I have somewhere I can look, so I got something out of this whole sordid mess. So thanks all! :)


(for the curious, the broken map::find() turned out to be due to a far-flung heap clobber. I shoulda realized Rational Purify wouldn't necessarily be accurate :mad: )

[on a related note I want to find the bastard on this team who decreed 'boost shared pointers are too difficult to read and use, just manage memory properly' and punch him/her in the god drat crotch]

Ciaphas fucked around with this message at 23:17 on Jul 30, 2010

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Hey I'm back with an ALL NEW QUESTION!

We're writing an app that needs to perform a lot of case-insensitive (ASCII only, no unicode) string comparisons during processing. A LOT. Our current method of case-insensitive checking is something like 50 seconds out of a 500 second run under optimized-compiled code. :gonk: So I thought I'd see if there was a more performance-oriented method of doing this that I could substitute in without a week's worth of effort.

Right now we have an ICTraits class that inherits from char_traits. In it eq and lt are overridden to call std::tolower on the characters they're comparing before returning their equality; compare is overridden to loop through the characters and check equality as you'd expect using the overridden eq and lt.

shrughes
Oct 11, 2008

(call/cc call/cc)

Ledneh posted:

Hey I'm back with an ALL NEW QUESTION!

We're writing an app that needs to perform a lot of case-insensitive (ASCII only, no unicode) string comparisons during processing. A LOT. Our current method of case-insensitive checking is something like 50 seconds out of a 500 second run under optimized-compiled code. :gonk: So I thought I'd see if there was a more performance-oriented method of doing this that I could substitute in without a week's worth of effort.

Consider these in the order 3 -> 4 -> 5 -> 6 -> 2 -> 1.

1. Could you save work by canonicalizing the strings to lowercase and then doing memcmp-style comparisons afterwards?

2. Could you save work by precomputing a checksum of the canonicalized strings and first comparing those, and then comparing if the checksums are equal? (If you are comparing for equality.)

3. Look at the generated assembly code. Is it inlining tolower or the character equality functions? (If not, get that inlined and try again.)

4. What's with the char_traits crap? (Everything is crap.) How does just writing the function manually work?

5. Do you really need to do all those string comparisons? If your comparisons are from using some std::map or binary search through an array or something like that, you could use a more appropriate data structure that doesn't net you a (log(n))^2 comparison cost. Hash tables are faster, have you tried those? If you're sorting, how about building some trie for the purpose? It doesn't take a week to build a fast trie datastructure, only a few hours.

6. Is the cost in byte-by-byte string comparisons, or is it in something else, like the cache inefficiency of your algorithm?


You might get more help if you tell use what goal requires all these string comparisons to happen.

ShoulderDaemon
Oct 9, 2003
support goon fund
Taco Defender
Are they just letters, or are there symbols too? Lowercasing a letter in ASCII is the same as bitwise or by 0x20, so you can do four-at-a-time by interpreting as an integer and doing bitwise or by 0x20202020, which might be marginally faster if your compiler isn't already doing it for you.

Similarly, you can do four comparisons at once by reinterpreting as an integer and doing the comparisons that way, if your compiler isn't already doing it for you. memcmp does this and sometimes other tricks really well.

But yeah, you're way better off giving us some way to help you avoid comparisons in the first place.

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


I'll be able to provide more information once I'm back at work on Tuesday. I did forget to mention though that the char_traits thing works because that way we can do typedef basic_string<ICTraits> ICString and just use that instead of std::string.

Long story short though, yes, we need to do the comparisons. There is literally no avoiding them. :(

(edit) Straight-up alphanumeric strings, with underscores if the folks making the data are feeling posh.

Ciaphas fucked around with this message at 02:26 on Aug 2, 2010

shrughes
Oct 11, 2008

(call/cc call/cc)

Ledneh posted:

Long story short though, yes, we need to do the comparisons. There is literally no avoiding them. :(

You haven't explained what you're doing. Why do you refuse to tell us? You obviously don't want help.

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Eh? I just didn't think it was important, chill. :(

We're reading in text files of about a gigabyte each, consisting of key-value pairs. We use the key/name to look up (currently in an oracle database) how to read and interpret the value (integer, float, literal string of fixed/variable length, hex characters to be reinterpreted as an int, a string to translate into a binary code, etc ad nauseum). Unfortunately no requirement for being consistent about case was ever established, and inertia means we have to take care of it. So we read in the key, call find on a map containing the data we've retrieved from the database (we've experimented with using boost::unordered_map too--not much help, at least according to the profiler), and use the value for getting the value read. (We just output these values in another format.)

The profiler has pretty consistently told us that the call to std::tolower() for string comparison was taking the longest of anything else.

Was that enough information?

Ciaphas fucked around with this message at 06:23 on Aug 2, 2010

ShoulderDaemon
Oct 9, 2003
support goon fund
Taco Defender
So it sounds like you don't, in fact, need to call tolower in your string comparison operator because you could just lowercase the key before running any comparisons, which will save a lot of work.

Similarly, is the in-memory map needed at all? If the information is already in a database, then just querying the database for each individual key may be significantly faster, especially if the database is local, as the people who wrote Oracle probably know a lot more about building intelligent indexes than you do.

OddObserver
Apr 3, 2009
Also, isn't tolower locale-sensitive? Using a simple specialized inline version may be measurably faster if that's that hot.

Edit #2: also, if you're using an std::map, you'll be doing a log number of comparisons, so you probably want to tolower once in advance.

OddObserver fucked around with this message at 06:40 on Aug 2, 2010

Sir Xiphos
Dec 11, 2008
If C# counts, I'd like to ask a question please.

I'm a first year Engineering student and we've been given the most ridiculous thing ever for a programming assignment. We're supposed to create a working version of Conway's Game of Life (http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) and I have no loving idea what to do. Right now, I'm trying to create the grid and somehow implement the MouseClick event handler in such a way that I can start filling in the grid with each click. That's all I want.

Any ideas? I'm sure at least some of you have made this at some point and I just need a bit of direction.

Dijkstracula
Mar 18, 2003

You can't spell 'vector field' without me, Professor!

There's a .NET megathread, but we can maybe point you in the right direction.

First of all, I don't see what is so ridiculous about this assignment. I'm pretty sure I had to do something similar when I was in my first year.

What have you done so far? What are your data definitions? How are you representing the GoL game world? Have you exposed enough of an API to your game world class that you can update cells within it? Have you implemented the actual GoL yet? (that is, can you apply the rules to each cell and transform to the next state?) Can you draw the game state on your form?

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


I hadn't considered looking up on the Oracle DB each time rather than preloading (and you are correct, it's local). I'll look into that on Tuesday.

All the entries in the database are stored lowercase--that's no problem, we maintain it--it's just that the incoming data can be any case the provider pleases, so we have to lower-case the read-in keys each time.

I haven't tired it, but wouldn't lowercasing the whole key then checking for string equality against the (already lowercase) map key amount to the same CPU load as lowercasing character by character (which we're doing now)?

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

Ledneh posted:

I haven't tired it, but wouldn't lowercasing the whole key then checking for string equality against the (already lowercase) map key amount to the same CPU load as lowercasing character by character (which we're doing now)?
Lowercasing the string first means you lowercase it once; lowercasing it in the comparison function means you lowercase it log N times. Unless you only have two items in your map, this is a pretty massive difference.

shrughes
Oct 11, 2008

(call/cc call/cc)
You could also get rid of all the std::tolower calls, replacing them with a string-lowering function that uses a static inline 256-byte lookup table or some simple thing that compiles to a conditional move to lowercase characters more efficiently, instead of some crazy locale thing (which probably boils down to a 256-byte lookup table inside a function call or two). I would try this, if you're spending all your time in the std::tolower function.

You could also try using boost::unordered_map or whatever hash table implementation you want using a very cheap hash function, instead of a robust one. How big is the map? It is a std::map?

Realize with all this effort you're only going to get a less than 10% speedup, since it's 50s out of 500.

shrughes fucked around with this message at 08:33 on Aug 2, 2010

epswing
Nov 4, 2003

Soiled Meat
shrughes beat me to it, but I'll say it anyways for emphasis: you're putting substantial effort towards a less-than-10% gain in speed.

Maybe it's time to look at improving the algorithm itself. Of course, I don't know anything about the algorithm, but I will ask this: does each string in your file have anything to do with any other string in the file? If not, you could consider parallelizing this.

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Oh I know it's less than 10% and that performance shouldn't be a concern and all that. I'm just thinking things over over the weekend, and thought I'd ask, so no effort expended at all :v:

epswing, for some files how to interpret later values depends on values retrieved earlier in the file, so we (and by we I mean my predecessors) decided rather early on to forget about multithreading. I doubt the poor application would stand up to adding it in now.

I already tried using unordered_map instead of map (in the last five minutes on Friday before I left :v: ), to little effect, but then I didn't provide a hash function beyond the default for std::string either.

Thanks all for all the thoughts and advice by the way, it's all much appreciated. :)

baquerd
Jul 2, 2007

by FactsAreUseless
Any resources on best practices regarding memory management for someone who rarely works in a language without an automatic garbage collector? Are there any pre-made solutions that will work out of box with code standardization or otherwise?

I understand pointers and low-level memory storage and management well enough in theory, but I've never had to put anything into practice outside of academics to know more than the most common mistakes made. I'm concerned with memory leaks on a process that will be running 24/7 pretty much.

Adahn the nameless
Jul 12, 2006
Suppose I have two classes, A and B, and a function. Class B is a friend of class A, and the function is a friend of class B. Can the function access A's private members?

Bonfire Lit
Jul 9, 2008

If you're one of the sinners who caused this please unfriend me now.

No. Friendship isn't transitive.

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.
I'm friends with John, and John is friends with Fred. Can I tickle Fred's balls?

Adahn the nameless
Jul 12, 2006
Gotcha, thanks. Then is it possible to declare a function as a friend of two classes? Or should I rethink my class design?

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.
Yeah, you just declare it as a friend in both classes. (I'm assuming that the function takes A and B as arguments.)

The more friends you add, the more likely it is that your class design is convoluted. What does the function do with the private data? Could you rewrite the function to just take the data that it needs as its arguments instead of A and B? Then it wouldn't need to be a friend.

Adahn the nameless
Jul 12, 2006

Mustach posted:

Yeah, you just declare it as a friend in both classes. (I'm assuming that the function takes A and B as arguments.)

The more friends you add, the more likely it is that your class design is convoluted. What does the function do with the private data? Could you rewrite the function to just take the data that it needs as its arguments instead of A and B? Then it wouldn't need to be a friend.

I guess I should break down what I'm trying to do. I'm trying to implement a singly linked list. I have two classes: a class "node" which holds the data for each node and the functions to manage the node (constructors, stream operators etc), and a class "linklist" which holds a pointer to the first element as well as functions to manage the list (insertion, constructors etc).

The function I'm having trouble with is an overloaded << operator for the linklist class. It needs to access the private node data to print it.

Most of the examples I find online implement the node as a structure. Is this preferable?

Flobbster
Feb 17, 2005

"Cadet Kirk, after the way you cheated on the Kobayashi Maru test I oughta punch you in tha face!"

Adahn the nameless posted:

I guess I should break down what I'm trying to do. I'm trying to implement a singly linked list. I have two classes: a class "node" which holds the data for each node and the functions to manage the node (constructors, stream operators etc), and a class "linklist" which holds a pointer to the first element as well as functions to manage the list (insertion, constructors etc).

The function I'm having trouble with is an overloaded << operator for the linklist class. It needs to access the private node data to print it.

Most of the examples I find online implement the node as a structure. Is this preferable?

Are the nodes completely managed by the linked list and never touched by client code? If so, make Node a private nested class inside LinkedList.

Adahn the nameless
Jul 12, 2006

Flobbster posted:

Are the nodes completely managed by the linked list and never touched by client code? If so, make Node a private nested class inside LinkedList.

I had intended the client code to call the node constructors, but I can change that. Maybe have a function in the "linklist" class call the node constructor?

HFX
Nov 29, 2004

Adahn the nameless posted:

I had intended the client code to call the node constructors, but I can change that. Maybe have a function in the "linklist" class call the node constructor?

The client of your linked list should not be touching a node class. The only thing the client should know is that it can put and remove items of the linked list.

The linked list is responsible for each node construction. There are some interesting design patterns you could get into on how you construct nodes internally, but your client should never construct nodes.

Adahn the nameless
Jul 12, 2006

HFX posted:

The client of your linked list should not be touching a node class. The only thing the client should know is that it can put and remove items of the linked list.

The linked list is responsible for each node construction. There are some interesting design patterns you could get into on how you construct nodes internally, but your client should never construct nodes.

So I should have a public function that creates and inserts the node in the linked list class call private functions in the node class? Could I transplant this same architecture to a template linked list class?

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

baquerd posted:

Any resources on best practices regarding memory management for someone who rarely works in a language without an automatic garbage collector? Are there any pre-made solutions that will work out of box with code standardization or otherwise?

The best practice is to work in C++ and use RAII for *everything*. Boost has some excellent smart-pointer libraries, or if necessary you can roll your own, but if you don't use RAII then resource management is really complicated.

In particular, if you're using exceptions and you're not using RAII then you are insane and wrong. If you're not using exceptions and not using RAII you are merely asking for a lot of trouble.

Brecht
Nov 7, 2009
I've got an ABNF spec for a protocol that is reasonably (but not extremely) complex. I need a decoder in straight C, but I haven't found something suitable in an existing library. Should I:
  • roll my own,
  • translate the ABNF grammar to something flex/bison can handle, or
  • have you all tell me about something I'm overlooking?

HFX
Nov 29, 2004

Adahn the nameless posted:

So I should have a public function that creates and inserts the node in the linked list class call private functions in the node class? Could I transplant this same architecture to a template linked list class?

Yes and Yes.

I'm trying to remember what books I used to recommend for C++. I think Ivor Hortons Visual C++ 6 was pretty good for learning the basics of C++ and Object Orientation (ignore second half of the book which is about MFC programming). I think there was an even better one, but it too would be done by Wrox. Once you have the basics, Professional C++ and the Bjarne Stroustrup book are worth reading. I think the Dietel & Dietel C and C++ book are good too (ignore the rest of their stuff).

Anyway, what you want to learn to do with an object oriented language like C++ is to hide details that are uninteresting to client code. Learn to have single responsibility principles. Example: Your node class for a linked list only needs to know its neighbor(s) and what it is storing. Your list class needs to know how to store nodes to ensure correct placement and retrieve items out of those nodes when asked.

Adbot
ADBOT LOVES YOU

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


rjmccall posted:

The best practice is to work in C++ and use RAII for *everything*. Boost has some excellent smart-pointer libraries, or if necessary you can roll your own, but if you don't use RAII then resource management is really complicated.

In particular, if you're using exceptions and you're not using RAII then you are insane and wrong. If you're not using exceptions and not using RAII you are merely asking for a lot of trouble.

Still wishing I could kick my coworkers in the junk for not letting me use shared_ptrs. :mad:

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