Go Back   RunUO - Ultima Online Emulation > Developer's Corner > Programming > C/C++

C/C++ C/C++ Discussion

Reply
 
Thread Tools Display Modes
Old 11-09-2006, 10:32 AM   #1 (permalink)
Forum Expert
 
milt's Avatar
 
Join Date: Nov 2003
Location: Hershey, PA
Age: 19
Posts: 1,601
Send a message via AIM to milt Send a message via Yahoo to milt Send a message via Skype™ to milt
Default C++ Arrays

Okay, so I know that in C#, I can create a class with a custom constructor, and then make an array of that class and call the constructors in the initialization. This may sound confusing, so I'll give an example.
Code:
public class Class1
{
     public string string1;

     public Class1(string s)
     {
          string1 = s;
     }
}

public class Class2
{
     public Class2()
     {
          Class1[] classes = new Class1[]
          {
               new Class1("Hello"), //Calling custom constructors in initialization of array
               new Class1("Goodbye")
          };
     }
}
What I am trying to do, is something similar in C++.
Code:
class Class1
{
     public:
          string string1;
          Class1(string s)
          {
               string1 = s;
          }
}
class Class2
{
     public:
          Class1 *classes;
          Class2()
          {
               classes = new Class1[] //Syntax error
               {
                    Class1("Hello"),
                    Class2("Goodbye")
               };
          }
          ~Class2()
          {
               delete [] classes;
          }
}
}

That C++ code gives me syntax errors in the initialization of "classes". What would be the best way to do what I am trying to do? I can't really seem to find a solution, so any help is appreciated.

Thanks
__________________
--Milt, AKA Pokey
milt is offline   Reply With Quote
Old 11-09-2006, 10:45 AM   #2 (permalink)
Forum Expert
 
Join Date: Jul 2005
Location: Istanbul/Turkey
Age: 27
Posts: 425
Default

try:

Class1 * classes=new Class1[2];

classes[0]=new Class1("asds");
classes[1]=new Class1("sads");
__________________
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."

Last edited by noobie; 11-09-2006 at 10:48 AM.
noobie is offline   Reply With Quote
Old 11-09-2006, 10:49 AM   #3 (permalink)
Forum Expert
 
arul's Avatar
 
Join Date: Jan 2005
Location: Hiding in your room.
Age: 21
Posts: 1,272
Send a message via MSN to arul
Default

Class1 classes[] = { Class1("Hello"), Class1("Goodbye") };
__________________
arul is offline   Reply With Quote
Old 11-09-2006, 11:58 AM   #4 (permalink)
Forum Expert
 
milt's Avatar
 
Join Date: Nov 2003
Location: Hershey, PA
Age: 19
Posts: 1,601
Send a message via AIM to milt Send a message via Yahoo to milt Send a message via Skype™ to milt
Default

Quote:
Originally Posted by arul
Class1 classes[] = { Class1("Hello"), Class1("Goodbye") };
Is it possible to use a pointer variable for this?
__________________
--Milt, AKA Pokey
milt is offline   Reply With Quote
Old 11-09-2006, 12:06 PM   #5 (permalink)
Forum Expert
 
milt's Avatar
 
Join Date: Nov 2003
Location: Hershey, PA
Age: 19
Posts: 1,601
Send a message via AIM to milt Send a message via Yahoo to milt Send a message via Skype™ to milt
Default

Well, now that I think of it... when you use the keyword 'new', it is allocating memory, so I guess at first it wouldn't know how much to allocate unless you specify the size inside the []. Am I corect?
__________________
--Milt, AKA Pokey
milt is offline   Reply With Quote
Old 11-09-2006, 12:25 PM   #6 (permalink)
Forum Expert
 
arul's Avatar
 
Join Date: Jan 2005
Location: Hiding in your room.
Age: 21
Posts: 1,272
Send a message via MSN to arul
Default

Quote:
Originally Posted by milt
Is it possible to use a pointer variable for this?
This is the only way I can think off atm.

Code:
Class1 *classes = (Class1 *) calloc( 2, sizeof(Class1) );

classes[0] = Class1("hey");
classes[1] = Class1("heeey");
__________________
arul is offline   Reply With Quote
Old 11-09-2006, 12:27 PM   #7 (permalink)
Forum Expert
 
Join Date: Jul 2005
Location: Istanbul/Turkey
Age: 27
Posts: 425
Default

yes, it is called dynamic allocation and if you use arul's (first) example, memory is allocated in compile time.

if you use C++, get used to pointers..
__________________
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."
noobie is offline   Reply With Quote
Old 11-09-2006, 12:34 PM   #8 (permalink)
Forum Expert
 
Join Date: Jul 2005
Location: Istanbul/Turkey
Age: 27
Posts: 425
Default

arul : if you are gonna do it in C-style, it is better to use malloc rather than calloc..

anyway, C is annoying, go with C++
__________________
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."
noobie is offline   Reply With Quote
Old 11-09-2006, 01:34 PM   #9 (permalink)
Forum Expert
 
Join Date: Feb 2005
Age: 24
Posts: 985
Send a message via AIM to Nochte
Default

an array and a pointer variable are basically synonymous terms.

by
Code:
Class1 classes[] = { Class1("Hello"), Class1("Goodbye") };
You are creating a pointer pointing at the first element of classes. In effect, you can use classes exactly like you would any other pointer.

Quote:
Originally Posted by noobie
anyway, C is annoying, go with C++
I agree..*gibbily gibbily gibbily*

Last edited by Nochte; 11-09-2006 at 01:36 PM.
Nochte is offline   Reply With Quote
Old 11-09-2006, 01:41 PM   #10 (permalink)
Forum Expert
 
Join Date: Aug 2004
Location: Redmond, WA
Age: 21
Posts: 1,288
Send a message via AIM to Sep102 Send a message via MSN to Sep102
Default

Technically, about the best way to do what you want to do is using malloc() with placement-new.

Code:
Class1 *classes = static_cast<Class1 *>(malloc(sizeof(Class1) * 2));

new(&classes[0]) Class1("Hello");
new(&classes[1]) Class1("Goodbye");
(By the way, in doing this, you're basically duplicating the functionality of new[]. The only difference being that you're avoiding the effort of default initializing the instances when you're going to be initializing them with a different constructor directly afterwards.)

This is, technically, the best way to do it as it avoids any unnecessary temporaries or initialization that the other examples had (of course, this is assuming the optimizer doesn't just get rid of them completely, which it may very well do). Of course, all of the other ways are easier to understand, thus they have their own merits (Except for noobie's of course, which leaks memory, if it were even valid to assign a Class1 * to a Class1 at all ).

However, as it is, none of the examples, which have been using milt's original Class1 definition, have been correct, other than mine and arul's. This is because when milt defined a constructor for Class1 that took a std::string parameter, he hid the default constructor for Class1, thus using new to create multiple Class1 objects is illegal as it requires Class1 to have a default constructor to call on each of the objects. Using malloc() (or calloc() for that matter) elides this restriction, as it doesn't call any constructors, it only allocates memory (including calloc(), though it does zero memory out for you).

Also, in arul's method, classes is a pointer variable, it just doesn't look like it. In C/C++, all arrays decay to pointer's, thus classes is usable in (almost) any place where a pointer would be allowed.

edit: Darn, Nochte beat me to my last statement.

Last edited by Sep102; 11-09-2006 at 02:03 PM.
Sep102 is offline   Reply With Quote
Old 11-09-2006, 01:47 PM   #11 (permalink)
Forum Expert
 
milt's Avatar
 
Join Date: Nov 2003
Location: Hershey, PA
Age: 19
Posts: 1,601
Send a message via AIM to milt Send a message via Yahoo to milt Send a message via Skype™ to milt
Default

Code:
class Calendar
{
public:
	int year;
	int month;
	Month *months;

	Calendar()
	{
		Month table[] =
		{
			Month("January", 31),
			Month("February", 28),
			Month("March", 31),
			Month("April", 30),
			Month("May", 31),
			Month("June", 30),
			Month("July", 31),
			Month("August", 31),
			Month("September", 30),
			Month("October", 31),
			Month("November", 30),
			Month("December", 31)
		};

		months = &table; //Line of error
	}

	~Calendar()
	{
		delete [] months;
	}
}
c:\Documents and Settings\JoshuaT\My Documents\Visual Studio Projects\Calendar\Calendar.cpp(52): error C2440: '=' : cannot convert from 'Month (*__w64 )[12]' to 'Month *'

I wanted to try it this way, but for some reason I keep getting that error. Shouldn't it technically work?
__________________
--Milt, AKA Pokey
milt is offline   Reply With Quote
Old 11-09-2006, 01:51 PM   #12 (permalink)
Forum Newbie
 
Join Date: Nov 2002
Posts: 89
Default

If I understand you correctly, you want to initliaze a class with a string?

Code:
#include <string>
class Class1
{
public:
     Class1(const std::string &="")

public:
    std::string s;
};
And the implementation

Code:
Class1::Class1(const std::string &var)
{
    s= var;
}
punt59 is offline   Reply With Quote
Old 11-09-2006, 01:53 PM   #13 (permalink)
Forum Expert
 
Join Date: Aug 2004
Location: Redmond, WA
Age: 21
Posts: 1,288
Send a message via AIM to Sep102 Send a message via MSN to Sep102
Default

If this were C, then yes, but C++ has stricter typing than C does, so no. What you're doing in this case is tring to assign a Month ** to a Month *. table in this case is a Month[12] or array of 12 Month objects, taking the address of that with (&) returns a pointer to a pointer to a Month, which, like I said, can't be assigned to a Month *.

Try:
Code:
months = &table[0];
Which assigns the address of the first element of table to months.

However, this code won't work as you think. You're trying to keep table around in memory for the life of the Calendar instance, however, using Month table[] = {...} is not the same thing as using Month *table = new Month[12] even though they're both pointers. table, as it is, sits on the stack for the duration of the constructor, then is automatically cleaned up, like any local variable is. Objects created using new or memory allocated using malloc() needs to be free'd or delete'd by you, which is why they stick around for as long as you want them to.

What you need to do is create table using new or malloc(), then initialize each element in it, then assign it to months, as then it will live on the heap, you can delete[] (or free()) it fine, and everything will be right in the world.

Last edited by Sep102; 11-09-2006 at 02:04 PM.
Sep102 is offline   Reply With Quote
Old 11-09-2006, 02:07 PM   #14 (permalink)
Forum Expert
 
milt's Avatar
 
Join Date: Nov 2003
Location: Hershey, PA
Age: 19
Posts: 1,601
Send a message via AIM to milt Send a message via Yahoo to milt Send a message via Skype™ to milt
Default

Okay, so basically I'm stuck with this?

Code:
class Calendar
{
public:
	int year;
	int month;
	Month *months;

	Calendar()
	{
		months = new Month[12];

		months[0] = Month("January", 31);
		months[1] = Month("February", 28);
		months[2] = Month("March", 31);
		months[3] = Month("April", 30);
		months[4] = Month("May", 31);
		months[5] = Month("June", 30);
		months[6] = Month("July", 31);
		months[7] = Month("August", 31);
		months[8] = Month("September", 30);
		months[9] = Month("October", 31);
		months[10] = Month("November", 30);
		months[11] = Month("December", 31);
	}

	~Calendar()
	{
		delete [] months;
	}
}
__________________
--Milt, AKA Pokey
milt is offline   Reply With Quote
Old 11-09-2006, 02:12 PM   #15 (permalink)
Forum Expert
 
Join Date: Aug 2004
Location: Redmond, WA
Age: 21
Posts: 1,288
Send a message via AIM to Sep102 Send a message via MSN to Sep102
Default

Pretty much, I can give you a "possibly" more appealing way that uses std::copy from the algorithm header, but that's about it.

Code:
#include <algorithm>

/*...*/

Calendar()
{
	Month table[] =
	{
		Month("January", 31),
		Month("February", 28),
		Month("March", 31),
		Month("April", 30),
		Month("May", 31),
		Month("June", 30),
		Month("July", 31),
		Month("August", 31),
		Month("September", 30),
		Month("October", 31),
		Month("November", 30),
		Month("December", 31)
	};
	
	months = new Month[12];

	std::copy(&table[0], &table[12], months);
}
std::copy copies from the iterator (pointer in this case) &table[0], or the first element of table, to one before the second argument of the function (&table[12]) or the last element of table. It copies this into the third argument, months.

Last edited by Sep102; 11-09-2006 at 02:18 PM.
Sep102 is offline   Reply With Quote
Old 11-09-2006, 02:23 PM   #16 (permalink)
Forum Expert
 
milt's Avatar
 
Join Date: Nov 2003
Location: Hershey, PA
Age: 19
Posts: 1,601
Send a message via AIM to milt Send a message via Yahoo to milt Send a message via Skype™ to milt
Default

Thank you all of you for the help... I'll send you a wad of $$ when I show up Gil Bates .

++karma

*edit* couln't give karma to everyone, sorry
__________________
--Milt, AKA Pokey

Last edited by milt; 11-09-2006 at 02:25 PM.
milt is offline   Reply With Quote
Old 11-09-2006, 02:52 PM   #17 (permalink)
Forum Expert
 
Join Date: Jul 2005
Location: Istanbul/Turkey
Age: 27
Posts: 425
Default

thats not a good example, you are wasting memory..

I would use something like this:

Code:
class Calendar{
	public:
		Month * table;
		Calendar()
		{
			table =new Month[12]; //have a default const for Month
			//initialize your private values
	
			table[0]=Month("January", 31);
			table[1]=Month("February", 28);
			table[2]=Month("March", 31);
			table[3]=Month("April", 30);
			table[4]=Month("May", 31);
			table[5]=Month("June", 30);
			table[6]=Month("July", 31);
			table[7]=Month("August", 31);
			table[8]=Month("September", 30);
			table[9]=Month("October", 31);
			table[10]=Month("November", 30);
			table[11]=Month("December", 31);
		}
		~Calendar()
		{
			delete [] table;
		}

};
__________________
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."

Last edited by noobie; 11-09-2006 at 02:55 PM.
noobie is offline   Reply With Quote
Old 11-09-2006, 03:04 PM   #18 (permalink)
Forum Expert
 
Join Date: Aug 2004
Location: Redmond, WA
Age: 21
Posts: 1,288
Send a message via AIM to Sep102 Send a message via MSN to Sep102
Default

Yes, it is wasting memory, for the duration of the constructor, then table is automatically cleaned up along with each of its entries while months sticks around with each of the entries on the heap, essentially trading "space" (constructing each month on the stack, which isn't very much of it in this case) and some time (default allocating months and copying table to months, still minuscule) for convenience.

I was trying to give an example that would use as much of milt's code as possible, had I wanted to give an optimized example, I would have, such as:
Code:
Month * table;
Calendar()
{
        // No need for default constructor and no extra work default
        // Constructing what we're about to reconstruct, yay!
	table = static_cast<Month *>(malloc(sizeof(Month) * 12));

	//initialize your private values, no temporaries here
        new(&table[0]) Month("January", 31);
	new(&table[1]) Month("February", 28);
	new(&table[2]) Month("March", 31);
	new(&table[3]) Month("April", 30);
	new(&table[4]) Month("May", 31);
	new(&table[5]) Month("June", 30);
	new(&table[6]) Month("July", 31);
	new(&table[7]) Month("August", 31);
	new(&table[8]) Month("September", 30);
	new(&table[9]) Month("October", 31);
	new(&table[10]) Month("November", 30);
	new(&table[11]) Month("December", 31);
}

~Calendar()
{
    for(Month *first = &table[0]; first != &table[12]; ++first)
    {
        first->~Month();
    }

    free(table);
}

I like the other example I gave more though, since it uses milt's code to construct the table on the stack and also looks quite a bit cleaner and easier to follow (especially from a more C# standpoint) than this or your example. Plus, you could just as easily have made table in some static const object that would contain all of the months for the life of the program that got copied to a member in Calendar each time a Calendar is constructed (if you want a mutable calendar, otherwise it could just hold a pointer to the table). All with minimal effort from what milt had above.

Last edited by Sep102; 11-09-2006 at 03:40 PM.
Sep102 is offline   Reply With Quote
Old 11-09-2006, 03:58 PM   #19 (permalink)
Forum Expert
 
Join Date: Jul 2005
Location: Istanbul/Turkey
Age: 27
Posts: 425
Default

well, I think that wasnt hard to understand and it is the most known syntax for memory allocation in C++, so he should get used to that one.

i have never used your syntax thb. and i tried that one just out of curiosity and it gives me a memory error "just after program exit" if you use strings instead of char*. so he needs to use C-style strings and all that stuff which is really not easy for a beginner.
__________________
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."

Last edited by noobie; 11-09-2006 at 04:10 PM.
noobie is offline   Reply With Quote
Old 11-09-2006, 04:58 PM   #20 (permalink)
Forum Expert
 
milt's Avatar
 
Join Date: Nov 2003
Location: Hershey, PA
Age: 19
Posts: 1,601
Send a message via AIM to milt Send a message via Yahoo to milt Send a message via Skype™ to milt
Default

Yeah, I was trying to stay basic here, as I have just started a college C++ course. I know the basic concepts of pointers and stuff, but not all of their functionality.

One of my first assignments is to make a console app that asks for a year and month, and will spit out a calendar for that month. You have to take leap years into account, etc... but that is the easy part TBH
__________________
--Milt, AKA Pokey
milt is offline   Reply With Quote
Old 11-09-2006, 06:37 PM   #21 (permalink)
Forum Expert
 
Join Date: Aug 2004
Location: Redmond, WA
Age: 21
Posts: 1,288
Send a message via AIM to Sep102 Send a message via MSN to Sep102
Default

You've never used the syntax because placement-new isn't really used all too often, at least as far as I've seen. It can be really useful when you actually need it, but in general standard new provides most of the functionality you would need (Or, at least, that's my take on the matter).

And, technically my (milt's) example uses the same method for memory allocation, I just construct the instances of the Month in a different way, closer to the way C# does it then copied them over to where I was going to persist them.

Really, you wouldn't do it your way either, in general, maybe (Probably not still though, if I was expecting to construct multiple objects at once as an array on the heap, I'd provide some Initialize() function or something of the sort rather than calling the constructor on each of them after allocating them), but at least in this instance it's not really a good idea to re-create the months every time, at least as it is. Like I said earlier, it would be a better idea to create them once then make a copy of them each time they're needed for a new instance (if it's mutable, of course), of which my example is very well suited to perform.

Last edited by Sep102; 11-09-2006 at 06:40 PM.
Sep102 is offline   Reply With Quote
Reply

Bookmarks


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off



Powered by vBulletin® Version 3.7.0
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.2.0 RC5