3D GUI
- Brynet-Inc
- Member
- Posts: 2426
- Joined: Tue Oct 17, 2006 9:29 pm
- Libera.chat IRC: brynet
- Location: Canada
- Contact:
I'm pretty afraid of my C...Tyler wrote:but i can't wait until the first time the safety protocols disengage for no apparent reason and cause my C++ to attack me.
With C++, it just shoots you once or twice. With C, it beats you to death with a mallet.
And well...assembly's a little too graphic to post here.
C8H10N4O2 | #446691 | Trust the nodes.
- Kevin McGuire
- Member
- Posts: 843
- Joined: Tue Nov 09, 2004 12:00 am
- Location: United States
- Contact:
- Colonel Kernel
- Member
- Posts: 1437
- Joined: Tue Oct 17, 2006 6:06 pm
- Location: Vancouver, BC, Canada
- Contact:
operator-> and operator* are very useful for implementing smart pointers. operator() is very useful for implementing functors. +, -, ++ and -- are useful for implementing iterators.hckr83 wrote:isn't that taking C++ too far...I personally can't see much any use for many of the operator overloads, and [] I can only see a use for in lists and tablesIf you use pointers with C++ overloaded class operators it can get tricky in some moments.
But operator overloading and pointers-to-objects don't mix well syntactically, as you've seen. Use references or just use the objects directly.
Top three reasons why my OS project died:
- Too much overtime at work
- Got married
- My brain got stuck in an infinite loop while trying to design the memory manager
- Kevin McGuire
- Member
- Posts: 843
- Joined: Tue Nov 09, 2004 12:00 am
- Location: United States
- Contact:
Well. I suppose for instance: vector math where you want to make the code a little more readable using some of the syntactic sugar C++ provides.I personally can't see much any use for many of the operator overloads.
Code: Select all
class cVec3
{
public:
float x, y, z;
cVec3();
cVec3(float _x, float _y, float _z);
~cVec3();
cVec3 operator-(const cVec3 &a);
void debug();
};
cVec3::cVec3()
{
}
cVec3::cVec3(float _x, float _y, float _z)
{
x = _x; y = _y; z = _z;
}
cVec3::~cVec3()
{
}
void cVec3::debug()
{
printf("%x: %f,%f,%f\n", this, x, y, z);
}
cVec3 cVec3::operator-(const cVec3 &a)
{
cVec3 r;
r.x = x - a.x;
r.y = y - a.y;
r.z = z - a.z;
return r;
}
int main(int argc, char *argv[])
{
cVec3 a(10.0, 10.0, 10.0), b(2.0, 2.0, 2.0), c;
/// The entire function call is broken down with optimization turned on (for GCC)
c = a - b;
c.debug();
return 1;
}
hmm...smart pointers just seem like too much overhead for such a commonly done thing(I tend to use too many pointers though)Colonel Kernel wrote:operator-> and operator* are very useful for implementing smart pointers. operator() is very useful for implementing functors. +, -, ++ and -- are useful for implementing iterators.hckr83 wrote:isn't that taking C++ too far...I personally can't see much any use for many of the operator overloads, and [] I can only see a use for in lists and tablesIf you use pointers with C++ overloaded class operators it can get tricky in some moments.
But operator overloading and pointers-to-objects don't mix well syntactically, as you've seen. Use references or just use the objects directly.
function objects?! I didn't even know you could do that! I don't see any practical application right now, but I'm sure there is some good use for it..
++ and -- I can actually see a use for in my list thingy...like being able to override the = operator and such....meh...kidna complicated though..lol
btw, Are templates well optimized? If they aren't, with each call to a template, you'd reproduce code...and with many calls, it could eventually be MBs of duplicate wasted code! (if your not careful)
- Kevin McGuire
- Member
- Posts: 843
- Joined: Tue Nov 09, 2004 12:00 am
- Location: United States
- Contact:
The machine output of using a template function. The part I will show you is where I call MyTest in the main function.
Here is the machine output for the main function. You should notice two instructions in italic and bold. They are the calls I made the C source to our MyTest function template. The interesting part is that you might mistakenly identify them as the same call but if you look closely you can see that the letter f in the first function name is replaced with a letter j in subsequent template function call. This means the compiler took our one template function and produced a version for each template parameter list we called it with.
The compiler may inline a template function, but it may also inline a non-template function. GCC has algorithms to determine when to and when not to inline. (I have no in depth understanding of this mechanism).
And, GCC will optimize a instance of a template function just like a normal function..
Code: Select all
template <class TYPE> TYPE MyTest(TYPE& a)
{
return a;
}
int main(int argc, char *argv[])
{
float a;
unsigned int b;
a = MyTest<float>(a);
b = MyTest<unsigned int>(b);
return 1;
}
Here is the machine output for the main function. You should notice two instructions in italic and bold. They are the calls I made the C source to our MyTest function template. The interesting part is that you might mistakenly identify them as the same call but if you look closely you can see that the letter f in the first function name is replaced with a letter j in subsequent template function call. This means the compiler took our one template function and produced a version for each template parameter list we called it with.
Here are the two functions it produced just so you can notice it only created one instance of each.lea 0x4(%esp),%ecx
and $0xfffffff0,%esp
pushl 0xfffffffc(%ecx)
push %ebp
mov %esp,%ebp
push %ecx
sub $0x14,%esp
lea 0xfffffff8(%ebp),%eax
mov %eax,(%esp)
call 8048420 <_Z6MyTestIfET_RS0_>
fstps 0xfffffff8(%ebp)
lea 0xfffffff4(%ebp),%eax
mov %eax,(%esp)
call 8048434 <_Z6MyTestIjET_RS0_>
mov %eax,0xfffffff4(%ebp)
mov $0x1,%eax
add $0x14,%esp
pop %ecx
pop %ebp
lea 0xfffffffc(%ecx),%esp
ret
So no it does not continually add overhead each time you make a function call, instead it just creates one instance of this function in machine output.08048420 <_Z6MyTestIfET_RS0_>:
8048420: 55 push %ebp
8048421: 89 e5 mov %esp,%ebp
8048423: 83 ec 04 sub $0x4,%esp
8048426: 8b 45 08 mov 0x8(%ebp),%eax
8048429: 8b 00 mov (%eax),%eax
804842b: 89 45 fc mov %eax,0xfffffffc(%ebp)
804842e: d9 45 fc flds 0xfffffffc(%ebp)
8048431: c9 leave
8048432: c3 ret
8048433: 90 nop
08048434 <_Z6MyTestIjET_RS0_>:
8048434: 55 push %ebp
8048435: 89 e5 mov %esp,%ebp
8048437: 8b 45 08 mov 0x8(%ebp),%eax
804843a: 8b 00 mov (%eax),%eax
804843c: 5d pop %ebp
804843d: c3 ret
804843e: 90 nop
804843f: 90 nop
The compiler may inline a template function, but it may also inline a non-template function. GCC has algorithms to determine when to and when not to inline. (I have no in depth understanding of this mechanism).
And, GCC will optimize a instance of a template function just like a normal function..
- Colonel Kernel
- Member
- Posts: 1437
- Joined: Tue Oct 17, 2006 6:06 pm
- Location: Vancouver, BC, Canada
- Contact:
What is such a commonly-done thing? Calling new and delete? Managing reference counts...? The overhead added by a smart pointer is negligible, because any worthwhile compiler will inline most of the smart pointer's methods. On the other hand, the benefits of using smart pointers are tremendous as they make it much more difficult to inject subtle memory leaks into your code during development.hckr83 wrote:hmm...smart pointers just seem like too much overhead for such a commonly done thing(I tend to use too many pointers though)
You should spend some time learning how to use the algorithms in the STL. In a nutshell, function objects make it easy to apply a custom operation over a collection in a generic way. For example, let's say you have a vector<Foo*>, and each Foo has a method getBar() that returns a pointer to the Bar belonging to that Foo. If you want to "strip" the Foos off and end up with a vector<Bar*>, you can do that easily by writing a short function object that just calls getBar() on a Foo, and then call std::transform() on your input and output vectors. It's quite nifty, at least for C++.function objects?! I didn't even know you could do that! I don't see any practical application right now, but I'm sure there is some good use for it..
This kind of technique is actually extremely common in functional programming languages, but they offer much better support for such things directly in the language via "lambda functions" (I don't want to oversimplify too much, but basically they're anonymous functions).
Yeah, iterators are complicated to implement properly. I wouldn't even bother. The point is that without overloading operator ++ and -- it would be impossible for the STL to provide generic algorithms that work on all kinds of containers, including plain-jane C arrays. But as far as implementing iterators goes, better the STL guys than me.++ and -- I can actually see a use for in my list thingy...like being able to override the = operator and such....meh...kidna complicated though..lol
In terms of speed, templates are very well optimized. Everything basically gets inlined. In terms of space, if you instantiate a template with many different types, then yes, it can consume a lot of space. As others have said, it's not per "call" though, it's per unique instantiation. For example, if you have a vector<Foo> and a vector<Bar>, the code for vector will be replicated once for each.btw, Are templates well optimized? If they aren't, with each call to a template, you'd reproduce code...and with many calls, it could eventually be MBs of duplicate wasted code! (if your not careful)
I've heard horror stories about crappy old C++ compilers on really old flavours of UNIX (which, unfortunately for me, are still in active use) that will copy template code for a particular instantiation once per .cpp file, and the linker fails to eliminate the duplicate code. I haven't verified this myself yet though.
Top three reasons why my OS project died:
- Too much overtime at work
- Got married
- My brain got stuck in an infinite loop while trying to design the memory manager