• No se han encontrado resultados

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 be

sizeof(class symbol)

. It's not. If if

symbol

is the base class in a derived class definition (say

class extended_symbol

) then when a

extended_symbol

is allocated, the

operator new

of

symbol

is called with the size of

extended_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 you

should 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.