Page 1 of 3

initalizing a class

Posted: Wed Aug 27, 2003 2:07 pm
by Adek336
Hey! My goal is to get some heap space for a class, and then initialize it.

class foo
{
...
public:
foo();
};

..

foo *bar;

bar = kmalloc(sizeof(foo));
bar.foo();

I get an error: calling type "foo" like a method.

Is this normal?

Cheers,
Adrian.

Re:initalizing a class

Posted: Wed Aug 27, 2003 3:52 pm
by Schol-R-LEA
Yes. Constructors are a special case of static member functions (I amlost said 'class methods'; this is what I get for playing around in Squeak earlier today!); they cannot be called as instance member functions, nor can they be used with a conventional memory allocator function (that is to say, they only work with [tt]new[/tt] for dynamic memory allocation). Constructors cannot be called explicitly except when an object is initialized; they cannot be run as ordinary functions. In any case, allocating memory directly for an object is a Bad Idea, as any destructor the class uses won't get called when the memory is deallocated, as it would be if [tt]delete[/tt] were used.

Keep in mind, however, that (if you used -ffreestanding and the other appropriate switches) there is no [tt]new[/tt] or [tt]delete[/tt] operators yet; therefore, you will need to create them. Following my copy of Thinking in C++ (1st ed.; you can read the second edition online at http://www.mindview.net/), you can do it something like this:

Code: Select all

// example new and delete implementations - not tested code

void* operator new(size_t sz)
{
  return kmalloc(sz);
}

void operator delete(void* m)
{
   kfree(m);
}
Once this is done, you can allocate the object as usual:

Code: Select all

bar = new foo();
... 
delete bar;
The compiler willl automagically pass the object size to [tt]new[/tt] and perform the constructor function after the memory is allocated.

Note that, if you don't want to set up a global versions of these operators yet (which you may not, if this is going to use the kernel allocator), you can use class-specific overloaded versions instead; see the Eckel book in question for more details.

One more thing: when using a pointer to an object, you use the indirect member operator ('->') instead of the direct member operator ('.') to access member functions and variables (not to be confused with the pointer-to-member operators, '.*' and '->*', which allow you to capture a pointer to a member from outside of the object itself, for those times when you really, really need to blow away object encapsulation).

Comments and corrections welcome.

Re:initalizing a class

Posted: Thu Aug 28, 2003 1:14 am
by Pype.Clicker
if i declare "bar" as a reference to a foo instance, can i still use new to allocate it ?

i mean, is

Code: Select all

foo &bar=new foo();
bar.anymethod();
some valid C++ code ?

Re:initalizing a class

Posted: Thu Aug 28, 2003 2:47 am
by Solar
Pype.Clicker wrote: if i declare "bar" as a reference to a foo instance, can i still use new to allocate it ?
The return value of new() is a pointer-to-object. To take a reference, you'd need an object. And you cannot delete() a reference. So: Close, but no cigar. ;-)

Hint: Read up about "placement new", e.g. at http://www.glenmccl.com/nd_cmp.htm

That might be what you are looking for.

Re:initalizing a class

Posted: Thu Aug 28, 2003 3:55 am
by Adek336
Ah, it works :) One thing interests me. Am I able to allocate an object using another class type:

Code: Select all

foo *bar = new john;
or
foo *bar = (foo*) new john;
Another thing is I need to declare a _Unwind_Resume. It does not seem it does anything I need, but perhaps?

Re:initalizing a class

Posted: Thu Aug 28, 2003 4:05 am
by Tim
Adek336 wrote: Ah, it works :) One thing interests me. Am I able to allocate an object using another class type:

Code: Select all

foo *bar = new john;
or
foo *bar = (foo*) new john;
Yes, if john inherits from foo, the top example is correct. The bottom example will *always* work, even if john doesn't inherit from foo, and is dangerous.
Another thing is I need to declare a _Unwind_Resume. It does not seem it does anything I need, but perhaps?
Sounds like something to do with exception handling. Add these to your gcc command line: (also disables RTTI)
[tt]-fno-rtti -fno-exceptions[/tt]

Re:initalizing a class

Posted: Thu Aug 28, 2003 4:15 am
by Adek336
I still need the _Unwind_Resume func. It is required in process::process(), which uses uses the new operator. When I comment it out, it is not needed, even if I use new in a non-constructing function.

Cheers,
Adrian.

Re:initalizing a class

Posted: Thu Aug 28, 2003 5:07 am
by Solar
Tim Robinson wrote: [

Code: Select all

foo *bar = new john;
or
foo *bar = (foo*) new john;
The bottom example will *always* work, even if john doesn't inherit from foo, and is dangerous.
Advise: Never use C-style casts in C++ code. C++ casts (static_cast<>, dynamic_cast<>, const_cast<>, reinterpret_cast<>) are more explicit, generate (better) error messages if used wrongly, and are searchable in your sources. There is never need for a C-style cast.
Another thing is I need to declare a _Unwind_Resume. It does not seem it does anything I need, but perhaps?
Sounds like something to do with exception handling.
Correct, it is a function involved with stack unwinding in case an exception is thrown.
It is required in process::process(), which uses uses the new operator. When I comment it out, it is not needed, even if I use new in a non-constructing function.
The default implementation of new() throws a bad_alloc exception in out-of-memory situations. Calling the compiler with -fno-exceptions probably doesn't help much if you still call a new() that does a throw().

Erm... which brings up the question, where does your compiler have its new() from in the first place? If you haven't defined it, it's not available to you in OS space (just like all the rest of the standard library) - you know that, yes?

Re:initalizing a class

Posted: Thu Aug 28, 2003 5:38 am
by Adek336
I did define the new/delete. Until I did so, the compiler told me that there was an unresolved symbol void *operator new(uint), so I doesn't use the standard one. Possibly the compiler adds a reference to unwind_resume in the code of my new without my knowledge.

And, what are the differences between a c++ cast and a c cast, and how do I do a c++ cast?

Cheers,
Adrian.

Re:initalizing a class

Posted: Thu Aug 28, 2003 5:48 am
by Adek336
BTW, I wonder if the following code would make ptr point at bar.y:

Code: Select all

class foo
 {
public:
uint_t x;
uint_t y;
}

foo bar;
uint_t *ptr;

ptr = &bar + 4;
What if instead of foo bar; I had

foo *bar;
bar = new foo;

ptr = bar + 4;
or

foo *bar;
bar = new[8] foo;

ptr = bar[2] + 4;?


Cheers,
Adrian.

Re:initalizing a class

Posted: Thu Aug 28, 2003 6:05 am
by Pype.Clicker
stop! do not even think about obtaining a pointer to a member variable from the pointer to the object! ...
You can't make assumptions on the way the compiler will arrange fields in the "instance structure". Moreover, you must take into account the optionnal Vtable pointer, and things like this.

If you need to learn more about how your C++ objects are effectively stored, check out the C++ ABI at codesourcery ...

and ... what about &(bar.y) ? It sounds like the most straightforward way to make a pointer on that variable ... but once again, this is against virtually every good practice principles of OO programming ...

Re:initalizing a class

Posted: Thu Aug 28, 2003 6:12 am
by Adek336
Ha, now this makes me a problem! So how can my assembler code access the members of class foo:

class foo
{
uint_t x;
uint_t y;
}
foo bar;
To date, I had a following way:

extern bar;

mov (bar + 4), %eax

For some reason, it stopped working when I added one more uint_t ??? perhaps it is just like you say. Am I allowed to access struct members this way (or will it crash like with classes).

Cheers,
Adrian.

Re:initalizing a class

Posted: Thu Aug 28, 2003 6:22 am
by Pype.Clicker
i would rather suggest you to write down a small "accessor" function (like u_int get_y() {return y;}) that you can call from assembler ...

hard-coding offsets of C structure members or C++ class member is bad practice unless you have a system to rewrite automagically your assembler code when your structure changes.

Re:initalizing a class

Posted: Thu Aug 28, 2003 6:37 am
by Adek336
that would slow down the scheduler, instead of incl x I would have to

push %eax
call getx
incl %eax
call setx
pop %eax

I will try the old way, becuase I can't afford funcs - too slow and complex.

Cheers,
Adrian

Re:initalizing a class

Posted: Thu Aug 28, 2003 6:38 am
by Solar
What are the differences between a c++ cast and a c cast, and how do I do a c++ cast?
Runtime-checked cast:

int i = dynamic_cast<int>(x);

Compile-time checked cast:

int i = static_cast<int>(x);

Unchecked cast (don't do this, hazardous!):

int i = reinterpret_cast<int>(x);

Const-to-non-const cast:

int i = const_cast<int>(x);

For further information, I strongly suggest getting a C++ reference (like Stroustrup, "The C++ Programming Language"), a library reference (like Josuttis, "The STL Standard Template Library", or the Dinkumware.com online reference), and at least reading the books "Effective C++", "More effective C++" and "Effective STL" by Scott Meyers.

C++ is a complex language, and you have to master it somewhat more than plain C to really make use of its power. Until you really understood C++, you should stick to C.

I second Pype's urgent advice not to assume the binary layout of a class. Use accessor functions!
Am I allowed to access struct members this way (or will it crash like with classes).
C++ structs are no different from C structs. Beware of alignment padding that might be added by the compiler.

I'd say, use the accessor functions C++ offers unless you have identified them to be a performance issue in a given case. They make your code much cleaner.