CAPITULO II ASPECTOS LEGALES
CONSIDERA USTED QUE CON EL NUEVO DE GOBIERNO SE ESTÁ REHABILITANDO AL DETENIDO?
The Problem: You have a small class that is frequently allocated and deallocated from the heap. The dynamic memory allocation calls are really slowing down your program. How can you speed things up?
The Hack: Make a custom new / delete for your class.
I should point that this hack is tricky and not easy to implement. You
should only use it if you're sure you know what you're doing and you're sure that new and delete are a problem for this class. Implementing this wrong can
corrupt memory or cause lots of other problems, so make sure you've read hacks Hack 80 and Hack 81 before you start.
To create your own new for a class all you have to do is to declare it as a local operator function. Here's an example:
// A very small class (good for local new / delete) class symbol {
private:
char symbol_name[8]; // .. usual member functions
void* operator new (unsigned int size) { if (size == sizeof(symbol)) { void* ptr = local_allocate(size); if (ptr != NULL) { return (ptr); } }
return (::new char[size]); }
Let's go through this step by step. First we have the function declaration:
void* operator new (unsigned int size) {
This defines a operator new that overrides the one built-in to C++. It takes one parameter, the size of the item to be allocated.
One mistake people make is that they assume that the when you create a object who's type is
class symbol
that the size of the object is going to besizeof(class symbol)
. It's not. If ifsymbol
is the base class in a derived class definition (sayclass extended_symbol
) then when aextended_symbol
is allocated, theoperator new
ofsymbol
is called with the size ofextended_symbol
.If you do not understand exactly what I just said, the don't do this
optimization until you do. I suggest you perform some experiments with custom new / delete operator using both base and derived classes. Do not try this hack in production code unless you fully understand what is going on!
We are going to assume that program allocates mostly variables of type symbol and that's what we want to optimize. But just in case someone decided to extend our class, we check the size.
if (size == sizeof(symbol)) {
If the size is not right, we'll fall through to the bottom of the program and use the system new to allocate the memory.
return (::new char[size]);
If the correct size is given to use, that means we are allocating a new
symbol
so we can use the optimized memory allocation:if (size == sizeof(symbol)) {
void* ptr = local_allocate(size);
We'll leave the implementation of
local_allocate
to you. It should be simple and fast. (If it's big a slow, what's the point of using it?) For example, the allocator could use a fixed memory array to hold the data. Since you have a fixed size item and know something about the expected allocate / free usage youshould be able to make a very efficient memory manager.
Whenever we do a custom new we need to do a custom delete as well:
static void delete(void* const ptr) { if (local_delete(ptr))
return; ::delete ptr }
One final note, read the next anti-hack before proceeding.
Anti-Hack 87: Creating a Customized new / delete
Unnecessarily
The Problem: The programmer thinks his program is slow and feels that a local new / delete will speed things up.
The Anti-Hack: Optimize your program by putting in your own new / delete.
Most of the time if you add in an optimization without running the program through a profiler and carefully analyzing it, you will optimize in the wrong
place. The new / delete hack is tricky and dangerous. You don't want to add it unless you know that it will speed up your program. That means you have to do your homework.
Far too often a person who thinks he's a hacker, but isn't will perform the local new / delete. A predictable series of results generally follows.
First the code breaks. That's because getting local new / delete operators to function right is tricky. (See the previous hack for details.) Because the
programmer has implemented new / delete wrong his program fails in
mysterious ways. Tracking these down takes time. Eventually he will give up or finally get a working local new / delete. Of course the project will fall behind schedule during this process.
After he finally gets the new memory management system debugged, he will discover that because he didn't do his homework and run a profiler, he just sped up class that not part of the time critical program flow. Thus the result is that the program is not any faster than when he started.
So the only thing he has to show for his effort is a skipped schedule. But what did he gain? He learned a important lesson in premature optimization. A lesson you don't have to learn the hard way because you read this anti-hack.
Anti-Hack 88: Using shift to multiple or divide by powers of 2
The Problem: Some people use left shift to multiple by 2, 4, and other powers of 2. They use right shift to divide by the same numbers.
For example the following two lines do the same thing:
i = j << 3; i = j * 8;
The Anti-Hack: Use shift to speed up calculations.
Real hackers multiply by 8 when they want to multiply by 8.
Back in the days when compilers were stupid and machines slow, if you multiplied by 8 the compiler generated multiply instructions. This could be quite slow as some machines didn't have a multiply instruction, so in order to perform this operation, a subroutine call was used.
People quickly discovered that you could use shift instead of multiply (or divide) when using a power of 2 (2,4,8,16....). The resulting code was much faster.
But machines have improved and so has compiler technology. If you need to do a multiply, do a multiply. The compiler will generate the fastest code possible to accomplish this operation.
All you do when using a shift instead of a multiply or divide is making your code more obscure. We've got way too much obscure code now, be clear and simple. Use multiple to multiply and divide to divide.