Page 1 of 3

Help with Cryptic C++ code

Posted: Fri Jan 13, 2006 12:58 am
by Neo
Can anyone explain what this code means?

Code: Select all

for (list<baseObject*>::const_iterator iter = base_m.begin(); iter != base_m.end(); ++iter)
I had a look and :o

Re:Help with Cryptic C++ code

Posted: Fri Jan 13, 2006 1:40 am
by Candy
Neo wrote: Can anyone explain what this code means?

Code: Select all

for (list<baseObject*>::const_iterator iter = base_m.begin(); iter != base_m.end(); ++iter)
I had a look and :o
Ripping this up into short bits of code:

Code: Select all

list<baseObject *>::const_iterator iter;
for (iter = base_m.begin(); iter != base_m.end(); ++iter) {...}
The first line declares an object of a type const_iterator, defined in class list, where list is instantiated with the template parameter baseObject *. This means, that it has an iterator over a list of baseObject pointers (it iterates over pointers, note that). It's called iter and it's local (not on the heap, but on the stack).

This iter object is then copied to from base_m.begin(), which is an iterator to the first object of the list. While it is not equal to base_m.end(), which is an iterator to the object one past the end of the list, it loops. Each loop, the iterator is incremented (which is overriden so that it just calls the operator++ function on the object) and that has the effect of making it point to the next object.

As it's used in prefix form, it's slightly more efficient. If you use a postfix (x++) you have to calculate the value of x+1 and store it in x, and then return the ORIGINAL value of x. That means, you have to back it up somewhere. For an int, you can just use a register for that, no harm done. If it's a huge object, you don't want to copy it without reason. Therefore, if you increment an object without using the return value, use the prefix form.

The function thereby iterates over all objects in the list sequentially until it hits the end, and then stops. The object itself is accessed as *iter.


Note the similarity of use with a normal pointer to baseObject *. You can increment it and decrement it (making it point to the previous or next element in the array) and you can "dereference" it, thereby giving you the "object" in the "array", which in this case itself is a pointer (you did note that, right?). So, use (*iter)->xyz() to call xyz on the object.

Re:Help with Cryptic C++ code

Posted: Fri Jan 13, 2006 7:57 am
by Solar
Let me start at a different point. Getting it explained from two directions is better than one. ;-)

[tt]list<typename T>[/tt] is a list of "T" objects. In our case, [tt]list<baseObject*>[/tt] is a list of pointers to baseObject.

Now, you don't know anything about how this "list" actually works internally. But you want to iterate through it. Luckily, the standard library defines a standard way to do so, and that is iterators.

On any standard container, you can define an iterator, or a const_iterator if you want to make sure the container isn't modified.

Code: Select all

list<baseObject*>::const_iterator iter;
That's just such a thing: An iterator on a list of baseObject pointers. This iterator can "point" to an object of type [tt]baseObject*[/tt]. You can dereference it with [tt]*iter[/tt], you can make it point to the next object in the container by incrementing it, you can compare it to other iterators on the same container.

It behaves, for all practical purposes, like a pointer into an array. For many of the standard containers, that is exactly what an iterator actually is. The good thing is, you don't have to know, really. It could be a hopelessly complex thing grabbing the next object over some kind of UDP network connection or something.

That is why you cannot initialize your iterator like a pointer, with, say, [tt]iter = &base_m[0];[/tt]. Luckily, the standard defines ways to do this, too: [tt]base_m.begin()[/tt] gives you an iterator pointing to the first element, [tt]base_m.end()[/tt] gives you an iterator pointing to an element - be careful now - one behind the last element in the container. That means, dereference [tt]base_m.end()[/tt], you die. ;)

Means, your code snippet is a loop that iterates through all elements of base_m, written as the C++ standard lib mandates.

And now you can surely tell me what this little snippet does:

Code: Select all

for (list<baseObject*>::const_reverse_iterator iter = base_m.rbegin(); iter != base_m.rend(); ++iter)
8)

Re:Help with Cryptic C++ code

Posted: Fri Jan 13, 2006 9:15 am
by Neo
Solar wrote:

Code: Select all

for (list<baseObject*>::const_reverse_iterator iter = base_m.rbegin(); iter != base_m.rend(); ++iter)
8)
Reverse iteration I guess. :)

Solar wrote: [tt]base_m.begin()[/tt] gives you an iterator pointing to the first element, [tt]base_m.end()[/tt] gives you an iterator pointing to an element - be careful now - one behind the last element in the container. That means, dereference [tt]base_m.end()[/tt], you die. ;)
By behind did you mean 'next' or 'previous'?

Re:Help with Cryptic C++ code

Posted: Fri Jan 13, 2006 10:04 am
by Kemp
The one after it, ie, one position further on past the end. That's why it's not safe to dereference it.

Re:Help with Cryptic C++ code

Posted: Tue Jan 17, 2006 5:02 am
by Neo
Yeah I did realize that. Just wanted to make sure it wasn't a communication problem ;)

Re:Help with Cryptic C++ code

Posted: Wed Jan 18, 2006 8:13 am
by Neo
Here's another line that I am not sure about

Code: Select all

void* data = buff.Data();
pRaw = new (data) RawMsgHdr; //what does this mean?

Re:Help with Cryptic C++ code

Posted: Wed Jan 18, 2006 8:20 am
by Solar
That's a "placement new". A RawMsgHdr object is created at the memory position that data points at. Pretty obscure mojo which I haven't seen used "in the wild" before.

Re:Help with Cryptic C++ code

Posted: Wed Jan 18, 2006 8:23 am
by Candy
Solar wrote: Pretty obscure mojo which I haven't seen used "in the wild" before.
Dito for me. It's also hard to consider any real situation in which you would want to do that. There are a few however, some of which are in OS development. IIRC, they do make changing your objects hard since placement new commonly indicates non-c++-aware software interacting with your software, which means that you cannot change the class instancevariable ordering or virtual functions by any extent.

Where did you find this?

Re:Help with Cryptic C++ code

Posted: Wed Jan 18, 2006 10:38 pm
by Neo
Actually I'm not very sure. I think its from some networking code.
I was seeing it for the first time and was not sure what it meant.

Re:Help with Cryptic C++ code

Posted: Wed Jan 18, 2006 11:39 pm
by Neo
Solar wrote: That's a "placement new". A RawMsgHdr object is created at the memory position that data points at. Pretty obscure mojo which I haven't seen used "in the wild" before.
So could this actually be done with a

Code: Select all

pRaw= (RawMsgHdr*)data;
instead??

Re:Help with Cryptic C++ code

Posted: Wed Jan 18, 2006 11:46 pm
by Candy
Neo wrote:
Solar wrote: That's a "placement new". A RawMsgHdr object is created at the memory position that data points at. Pretty obscure mojo which I haven't seen used "in the wild" before.
So could this actually be done with a

Code: Select all

pRaw= (RawMsgHdr*)data;
instead??
No. It's an explicit call for a constructor on a previously-allocated area. This only makes it a pointer but doesn't call the constructor.

Placement new is only useful when you need a specific class at a given specific location, say, when using special memory for something. You could use it for creating an object in stuff allocated with SHMEM, then pass the shmem to another process and it'd just cast the memory and have the object initialized (note that you have to account for more than just these few things - there's more between processes than just memory).

Re:Help with Cryptic C++ code

Posted: Thu Jan 19, 2006 12:45 am
by Colonel Kernel
I'm pretty sure placement new is used in most STL implementations for things like default-constructing the elements of a vector in the space allocated using a particular allocator. I've also seen it used in some home-grown C++ garbage collectors. It's rare in application-level code though.

Re:Help with Cryptic C++ code

Posted: Thu Jan 19, 2006 7:56 am
by Kemp
Wow, I've never seen that before, I don't think any of the books/online material I've read have mentioned it. Though seeing what it does I can understand why.

Re:Help with Cryptic C++ code

Posted: Thu Jan 19, 2006 7:59 am
by Solar
Col. Kernel is right, though - STL style allocater functions would be a point where placement new would come in handy. I've never seen anyone actually using the option of defining your own allocator functions, either... (You'd probably do this if you were optimizing like hell, but who does these days where labor is expensive, but better hardware is cheap...) ;)