Login
User Name:

Password:



Register

Forgot your password?
Changes list / Addchange
Author: Khonsu
Submitted by: Khonsu
6Dragons mp3 sound pack
Author: Vladaar
Submitted by: Vladaar
AFKMud 2.2.3
Author: AFKMud Team
Submitted by: Samson
SWFOTEFUSS 1.5
Author: Various
Submitted by: Samson
SWRFUSS 1.4
Author: Various
Submitted by: Samson
Users Online
Sogou

Members: 0
Guests: 27
Stats
Files
Topics
Posts
Members
Newest Member
488
3,788
19,631
595
Khonsu

Today's Birthdays
There are no member birthdays today.
» SmaugMuds » General » Coding » A nice fat stumper for you all
Forum Rules | Mark all | Recent Posts

A nice fat stumper for you all
< Newer Topic :: Older Topic >

Pages:<< prev 1 next >>
Post is unread #1 Mar 19, 2006 11:27 pm   Last edited Mar 19, 2006 11:28 pm by Samson
Go to the top of the page
Go to the bottom of the page

Samson
Black Hand
GroupAdministrators
Posts3,685
JoinedJan 1, 2002

 
struct weapontable
{
   weapontable();

   char *flags;  /* Default flag set */
   char *name;   /* Descriptive name */
   float weight; /* Base weight */
   float cost;   /* Base cost/value */
   short type;   /* Weapon type */
   short wd;     /* Base damage */
   short skill;  /* Skill type */
   short damage; /* Damage type */
};

vector w_table;

weapontable::weapontable()
{
   init_memory( &flags, &damage, sizeof( damage ) );
}

void save_weapontable()
{
   ofstream stream;

   stream.open( WTYPE_FILE );
   if( !stream.is_open() )
   {
      log_string( "Couldn't write to weapontypes file." );
      return;
   }

   for( int x = 0; x < TWTP_MAX; ++x )
   {
      stream << "#WTYPE" << endl;
      stream << "Type   " << weapon_type[x].type << endl;
      stream << "Name   " << weapon_type[x].name << endl;
      stream << "WD     " << weapon_type[x].wd << endl;
      stream << "Weight " << weapon_type[x].weight << endl;
      stream << "Cost   " << weapon_type[x].cost << endl;
      stream << "Skill  " << weapon_type[x].skill << endl;
      stream << "Damage " << weapon_type[x].damage << endl;
      stream << "Flags  " << weapon_type[x].flags << endl;
      stream << "End" << endl << endl;
   }
   stream.close();
}

void load_weapontable()
{
   ifstream stream;
   weapontable *wt;

   w_table.clear();

   stream.open( WTYPE_FILE );
   if( !stream.is_open() )
   {
      log_string( "Couldn't read from weapontypes file." );
      return;
   }

   do
   {
      string key, value;
      char buf[MSL];

      stream >> key;
      strip_lspace( key );

      stream.getline( buf, MSL );
      value = buf;
      strip_lspace( value );

      if( key == "#WTYPE" )
         wt = new weapontable;
      else if( key == "Type" )
         wt->type = atoi( value.c_str() );
      else if( key == "Name" )
         wt->name = STRALLOC( value.c_str() );
      else if( key == "WD" )
         wt->wd = atoi( value.c_str() );
      else if( key == "Weight" )
         wt->weight = atoi( value.c_str() );
      else if( key == "Cost" )
         wt->cost = atoi( value.c_str() );
      else if( key == "Skill" )
         wt->skill = atoi( value.c_str() );
      else if( key == "Damage" )
         wt->damage = atoi( value.c_str() );
      else if( key == "Flags" )
{
         wt->flags = STRALLOC( value.c_str() );
log_printf( ".... %s", wt->flags );
}
      else if( key == "End" )
         w_table.push_back( wt );
   }
   while( !stream.eof() );
   stream.close();
}

CMDF( do_wtsave )
{
   save_weapontable();
   ch->print( "Done.\r\n" );
}

CMDF( do_wtload )
{
   load_weapontable();
   for( int x = 0; x < w_table.size(); ++x )
   {
      weapontable *w = w_table[x];

      log_printf( "Type %d, Name %s, WD %d, Weight %d, Cost %d, Skill %d, Damage %d, Flags %s",
         w->type, w->name, w->wd, w->weight, w->cost, w->skill, w->damage, w->flags );
      ch->printf( "Type %d, Name %s, WD %d, Weight %d, Cost %d, Skill %d, Damage %d, Flags %s\r\n",
         w->type, w->name, w->wd, w->weight, w->cost, w->skill, w->damage, w->flags );
   }
}

Data file:

#WTYPE
Type   0
Name   Not Defined
WD     0
Weight 0
Cost   0
Skill  0
Damage 0
Flags  brittle
End

#WTYPE
Type   1
Name   Dagger
WD     4
Weight 4
Cost   200
Skill  2
Damage 6
Flags  anticleric antimonk metal
End

#WTYPE
Type   2
Name   Claw
WD     5
Weight 4
Cost   300
Skill  4
Damage 1
Flags  anticleric antimonk metal
End

#WTYPE
Type   3
Name   Shortsword
WD     6
Weight 6
Cost   500
Skill  1
Damage 6
Flags  anticleric antimonk antimage antinecro antidruid metal
End

#WTYPE
Type   4
Name   Longsword
WD     8
Weight 10
Cost   800
Skill  1
Damage 1
Flags  anticleric antimonk antimage antinecro antidruid metal
End

#WTYPE
Type   5
Name   Claymore
WD     10
Weight 20
Cost   1600
Skill  1
Damage 1
Flags  anticleric antimonk antimage antinecro antidruid antibard antirogue twohand metal
End

#WTYPE
Type   6
Name   Mace
WD     8
Weight 12
Cost   700
Skill  5
Damage 4
Flags  antimonk antimage antinecro antirogue metal
End

#WTYPE
Type   7
Name   Maul
WD     10
Weight 24
Cost   1500
Skill  5
Damage 4
Flags  antimonk antimage antinecro antirogue twohand metal
End

#WTYPE
Type   8
Name   Staff
WD     7
Weight 8
Cost   600
Skill  11
Damage 4
Flags  twohand
End

#WTYPE
Type   9
Name   Axe
WD     9
Weight 14
Cost   800
Skill  9
Damage 3
Flags  anticleric antimonk antimage antinecro antidruid antirogue metal
End

#WTYPE
Type   10
Name   War Axe
WD     11
Weight 26
Cost   1600
Skill  9
Damage 3
Flags  anticleric antimonk antimage antinecro antidruid antirogue twohand metal
End

#WTYPE
Type   11
Name   Spear
WD     7
Weight 10
Cost   600
Skill  10
Damage 7
Flags  antimage anticleric antinecro twohand
End

#WTYPE
Type   12
Name   Pike
WD     9
Weight 15
Cost   900
Skill  10
Damage 7
Flags  anticleric antimonk antimage antinecro antidruid antirogue twohand
End

#WTYPE
Type   13
Name   Whip
WD     5
Weight 2
Cost   150
Skill  3
Damage 5
Flags  antimonk organic
End



Saavy users might recognize this bit of code, but if not, no worries. Whenever the wtload command is executed, the result is a segmentation fault. The log message displayed last is:

Sun Mar 19, 2006 9:19:46 PM PST :: Samson returns from beyond the void.
Sun Mar 19, 2006 9:19:49 PM PST :: .... brittle
Sun Mar 19, 2006 9:19:49 PM PST :: .... anticleric antimonk metal
Sun Mar 19, 2006 9:19:49 PM PST :: .... anticleric antimonk metal
Sun Mar 19, 2006 9:19:49 PM PST :: .... anticleric antimonk antimage antinecro antidruid metal
Sun Mar 19, 2006 9:19:49 PM PST :: .... anticleric antimonk antimage antinecro antidruid metal
Sun Mar 19, 2006 9:19:49 PM PST :: .... anticleric antimonk antimage antinecro antidruid antibard antirogue twohand metal
Sun Mar 19, 2006 9:19:49 PM PST :: .... antimonk antimage antinecro antirogue metal
Sun Mar 19, 2006 9:19:49 PM PST :: .... antimonk antimage antinecro antirogue twohand metal
Sun Mar 19, 2006 9:19:49 PM PST :: .... twohand
Sun Mar 19, 2006 9:19:49 PM PST :: .... anticleric antimonk antimage antinecro antidruid antirogue metal
Sun Mar 19, 2006 9:19:49 PM PST :: .... anticleric antimonk antimage antinecro antidruid antirogue twohand metal
Sun Mar 19, 2006 9:19:49 PM PST :: .... antimage anticleric antinecro twohand
Sun Mar 19, 2006 9:19:49 PM PST :: .... anticleric antimonk antimage antinecro antidruid antirogue twohand
Sun Mar 19, 2006 9:19:49 PM PST :: .... antimonk organic
Sun Mar 19, 2006 9:19:49 PM PST :: Type 0, Name Not Defined, WD 0, Weight 0, Cost 0, Skill 0, Damage 0, Flags (null)


That is obviously in the wtload command, suggesting it loaded the data in properly. However the log output says otherwise since the flags value turned NULL. Valgrind bitches about address 0x2 not being allocated, no surprise, it's crashing, I figured that much. The stack is smashed, so a core dump is worthless and Valgrind is of no value once the stack is smashed.

My best guess is that I'm using vector improperly, but I can't see how. Anyone have any ideas?

Post is unread #2 Mar 20, 2006 8:48 am   
Go to the top of the page
Go to the bottom of the page

Samson
Black Hand
GroupAdministrators
Posts3,685
JoinedJan 1, 2002

 
Don't know why I didn't try this before, but I threw the code up on Cygwin and had at it. Since it uses older gcc 3.4.4, I figured it might ferret out a potential compiler problem. Well, that's exactly what this turned out to be. Without altering a single line of code, Cygwin compiled it and ran it without crashing. Which is why I was stumped. Perfectly valid code crashing out for no explainable reason.

I'd file a bug against the compiler for this, but I wouldn't know where to begin. Isolating this for a testcase would be next to impossible. Guess we'll just have to hope that gcc 4.1 fixes this.

Post is unread #3 Dec 8, 2007 6:26 pm   
Go to the top of the page
Go to the bottom of the page

Quixadhal
Conjurer
GroupMembers
Posts398
JoinedMar 8, 2005

 
Samson said:

struct weapontable
{
   weapontable();

   char *flags;  /* Default flag set */
   char *name;   /* Descriptive name */
   float weight; /* Base weight */
   float cost;   /* Base cost/value */
   short type;   /* Weapon type */
   short wd;     /* Base damage */
   short skill;  /* Skill type */
   short damage; /* Damage type */
};

vector w_table;

weapontable::weapontable()
{
   init_memory( &flags, &damage, sizeof( damage ) );
}


I'm not a C++ guru, but can you have constructors in structs? At a guess, I'd say unless you change that to be a class, the compiler shouldn't be generating a call to the constructor function, which would thus not be calling init_memory().

cygwin probably doesn't barf on it because windows allocates auto-variables differently and thus instead of causing a seg-fault, it just reads from (or writes to) other memory owned by the process. For that matter, the windows kernel may not even enforce proper memory boundaries if the process is run by a user with administrator privs.

Post is unread #4 Dec 8, 2007 10:26 pm   
Go to the top of the page
Go to the bottom of the page

Samson
Black Hand
GroupAdministrators
Posts3,685
JoinedJan 1, 2002

 
Heh. The joy of old posts. At some point I figured out what was wrong with this since the test command loads and outputs what I was expecting it to. It's too bad the rest of my code is in such disarray at the moment or I might be able to remember why I was doing this to begin with.

Post is unread #5 Dec 10, 2007 1:06 am   
Go to the top of the page
Go to the bottom of the page

David Haley
Sorcerer
GroupMembers
Posts903
JoinedJan 29, 2007

 
It's perfectly fine to have constructors in structs. A class is nothing more than a struct with visibility modifiers. The problem is that if you initialize an object with malloc, the constructor is not called. You need to initialize it with 'new' if you want the constructor to be called. (Similarly for destroying it with free vs. delete.)

Post is unread #6 Jun 22, 2008 12:22 pm   Last edited Jun 22, 2008 12:37 pm by Noplex
Go to the top of the page
Go to the bottom of the page

Noplex
Apprentice
GroupMembers
Posts62
JoinedAug 30, 2005

 
DavidHaley said:

You need to initialize it with 'new' if you want the constructor to be called.


If you need a pointer you need to initialize it with new. The default constructor (if one exists) will be called as long as you don't allocate a block of memory with malloc. A constructor will also be called, if one exists, if an assignment operation is used and there is no explicit keyword before the constructor.

Examples:
class foo
{
public:
  foo(void) { std::cout << "default" << std::endl; }
  foo(int a) { std::cout << "int" << std::endl; }
  explicit foo(long b) { std::cout << "long" << std::endl; }
};

  int main(void)
  {
    foo a; // default
    
    foo b = 5; // int

    foo* c = new foo; // default

    foo* d = (foo*)malloc( sizeof(foo) ); // none

    foo f = (long)10; // none

    foo g( (long)10 ); // long

    return 0;
  }


Also, I might be remembering wrong but I believe CREATE used calloc and not malloc. The difference being is that calloc does not initialize the memory block. You will need to use memset if you need it initialized. If you require special memory allocation for an object the best method to go about it is to overload the new and delete operators (and not use macros). It may sound ass-backwards, but the way that new and delete were designed they did not replace malloc/calloc and free, but merely used them in the background. Personally, I don't see a reason to ever need to use malloc/free outside of a C application anymore.

This wasn't intended to say that David was wrong, I was merely elaborating. Bored, I guess, ;-)

Post is unread #7 Jun 22, 2008 1:57 pm   
Go to the top of the page
Go to the bottom of the page

Samson
Black Hand
GroupAdministrators
Posts3,685
JoinedJan 1, 2002

 
Ooo, double thread necromancy! That's gotta be worth some extra points or something :P

From "man calloc":
calloc() allocates memory for an array of nmemb elements of size bytes each and returns a pointer to the allo-cated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().

malloc() allocates size bytes and returns a pointer to the allocated memory. The memory is not cleared. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().


Unless the man page is wrong, calloc initializes the memory. Which means it's a good thing that CREATE wraps calloc. It's malloc that doesn't initialize the block, which I'd suspect is why it isn't used much anymore.

But then, most people are using C++ these days anyway and calloc/malloc aren't in play anymore. At least one would hope they're using new/delete.

Post is unread #8 Jun 22, 2008 2:23 pm   Last edited Jun 22, 2008 2:32 pm by Noplex
Go to the top of the page
Go to the bottom of the page

Noplex
Apprentice
GroupMembers
Posts62
JoinedAug 30, 2005

 
Samson said:


From "man calloc":
calloc() allocates memory for an array of nmemb elements of size bytes each and returns a pointer to the allo-cated memory. The memory is set to zero. If nmemb or size is 0, then calloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().

malloc() allocates size bytes and returns a pointer to the allocated memory. The memory is not cleared. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().


Yes, that'd be right. I haven't worked with actually allocating memory for a couple of years. My bad :-)

The only time you'll use malloc/calloc/realloc in C++ is when you're overloading the new operator (same thing with free). I have not come across a reason to use those instead of new/delete, and from what I know they merely wrap a call to malloc and then calls the specified constructor. It also throws an std exception (I don't remember the name offhand). I also believe that when new is called it almost always returns an unallocated block of memory off the heap (e.g. there is no realloc in the STL implementation). But I could be wrong :-)

But its important to point out that new has similar functionality to malloc -- it does not initialize to zero -- and therefore you must do that in the constructor (or better - in an initialization list). So, in an instance with a struct with no defined default constructor the block of memory will be uninitialized.

Post is unread #9 Jun 23, 2008 10:54 am   Last edited Jun 23, 2008 10:54 am by David Haley
Go to the top of the page
Go to the bottom of the page

David Haley
Sorcerer
GroupMembers
Posts903
JoinedJan 29, 2007

 
Well, actually, when you call 'new', it also calls the constructor of every member object of the object. For instance, if you have a struct that contains string objects, creating one with 'new' will initialize those string objects correctly. That is the default behavior. Note that this does not apply to pointers.

As a minor correction to my remark from a few months ago, the constructor is also called if you create something on the stack, e.g. for:

string s;
string*s = new string();

both call the constructor.

Post is unread #10 Sep 5, 2008 5:54 am   
Go to the top of the page
Go to the bottom of the page

Kylotan
Fledgling
GroupMembers
Posts37
JoinedNov 28, 2007

 
It'll call constructors for any non-POD type, but it won't do it for basic types. So your ints and so on will still be uninitialised.

Post is unread #11 Sep 5, 2008 10:48 am   
Go to the top of the page
Go to the bottom of the page

David Haley
Sorcerer
GroupMembers
Posts903
JoinedJan 29, 2007

 
You're right, I should have made it more clear that when I said 'member object', the word 'object' was very deliberately chosen. :wink:

That said, some container types over primitives like int etc. will call the constructor (initializer might be a more appropriate term) when they find that they need to insert objects, e.g. to fill up space in a vector if you inserted past the last element. But that's different from new's behavior.

Pages:<< prev 1 next >>