Jump to content
  • Advertisement
Sign in to follow this  
xidis

type-casting pointers

This topic is 4842 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I was looking through some of the articles here on gamedev.net and I stumbled upon this code:
namespace nTreeData
{
   const int kMaxLeaves = 10;
   const int kMaxDepth = 5;
}

class Leaf
{
public:

   Leaf() : value_(0) {}
   explicit Leaf(const int &value) : value_(value) {}

   const int &value() const { return value_; }

   bool operator==(const Leaf &rhs) const
      { return this->value() == rhs.value(); }
   bool operator<(const Leaf &rhs) const
      { return this->value() < rhs.value(); }

private:
   int value_;
};

#include <map>
#include <iostream>

typedef std::map<Leaf, int> LeafMapConcrete;
typedef std::map<Leaf, int>* LeafMapPointer;
typedef std::map<Leaf, LeafMapPointer > LeafMap;

void fun()
{
   using namespace nTreeData;
   LeafMap leafTree;

   ////////////////////////////////////////////////////
   // create a simple leaf tree
   ////////////////////////////////////////////////////
   for (int i = 0; i < kMaxLeaves; ++i)
   {
      // insert a starter leaf
      LeafMapPointer p = new LeafMapConcrete;
      leafTree.insert(LeafMap::value_type(Leaf(i), p));
      LeafMap::iterator iter = leafTree.find(Leaf(i));

      // continue inserting children inside of children
      for (int depth = 0; depth < kMaxDepth; ++depth)
      {
         LeafMapPointer inner = new LeafMapConcrete;
         LeafMap* outer = (LeafMap*)(iter->second);
         outer->insert(LeafMap::value_type(Leaf(depth), inner));

         iter = outer->find(Leaf(depth));
      }
   }

   ////////////////////////////////////////////////////
   // deallocate the leaf tree
   ////////////////////////////////////////////////////
   for (LeafMap::iterator destroy = leafTree.begin();
        destroy != leafTree.end();
        ++destroy)
   {
      LeafMap::const_iterator inner = destroy;
      LeafMap* iterMap = (LeafMap*)(destroy->second);
      LeafMap* lastMap;

      for (inner = iterMap->begin(); inner != iterMap->end();
           inner = iterMap->begin())
      {
         lastMap = iterMap;
         // move the iterMap forward
         iterMap = (LeafMap*)inner->second;
         delete lastMap;
      }
   }   
}


My question is what exactly is happening when one type casts LeafMapPointer to pointer to LeafMap? Insert is called on the converted pointer and it seems that one can insert a Leaf and a pointer even though the class that LeafMapPointer points to (LeafMapConcrete) takes a Leaf and an int? I have also seen this code:
int x;
char* p = &x;
char[0] = 0xff;
char[1] = 0x01;
char[2] = 0xa3;
char[3] = 0xbb;


I believe what is happening here is that the int is being assingned byte by byte. Any help is appreciated. Thanks. xidis

Share this post


Link to post
Share on other sites
Advertisement
Pointers store memory addresses. On most computers with most compilers, the pointer representation is just an number that is the memory address. 0 for the null pointer, and some positive number for other addresses. When you have a compiler where the size of an int is the same as the size of a pointer, you can cast an int to a pointer and vice versa without losing any information. This is generally bad mojo and you better know what you're doing before you rely on code that does this, but it can be useful at times.

Though judging from that code snippet this isn't one of the times it's really necessary. I don't know why the author used such an ugly hack.

The second one has the int being assigned byte by byte. However, this may not do what you expect on your hardware. Integers representations on computer hardware come in two flavors: little endian or big endian. Wintel computers are little endian and PowerPC Macs are big endian. Endianess determines which byte is least significant and which byte is most significant. Little endian computers put the least significant byte first. This makes casts between integer types easier. Big endian computers put the most significant byte first. This makes more logical sense if you look at the binary layout. So the byte by byte assignment may be for making an endian independent storage of the int. Or it could be for some other reason. Without seeing more context on the code it's hard to tell; but endianess is the most likely reason.

Share this post


Link to post
Share on other sites
The first snippet is abit of an atrocity for various reasons i'll explain shortly.

The bit your confused with the one with the cast, that cast is using a C-style cast which you in general should completely avoid in C++ use C++ cast operators, in this case the cast is no doubt equivalent to reinterpret_cast an unsafe, non-portable cast, a blind cast.

The reason why that may just about work for you is a pointer is a variable that holds the address of other variables in memory, a memory address is just an integral value (i don't mean type) so techincally you can store that value in an int assuming an int is large enough to hold all valid addresses of a pointer to a particular type. So basically he/she is making the assumption that a std::map<Leaf, int> is equivalent to std::map<Leaf, LeafMapPointer> because he/she views an LeafMapPointer as just an int.

Something not related to your problem and not a syntactic problem but one of efficiency, every time he/she inserts a new element he/she then uses std::map::find to get an iterator to where the new element was inserted but that is naive and unnecessarilly redundant as that version of std::map::insert returns an std::pair<std::map::iterator, bool> hence it already gives an iterator to the newly inserted element (if an insertion was made) without a need to search for it.

The second snippet is just not portable [grin].

The first snippet is really bad, its not even a cute trick i suggest looking else where.

[Edited by - snk_kid on August 20, 2005 5:06:15 PM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!