[Ayuda] Error con delete[]... algo extraño...

Iniciado por BlackZeroX, 7 Julio 2011, 23:33 PM

0 Miembros y 2 Visitantes están viendo este tema.

Khronos14

#10
¿Como ves mejor tu código?

Así:

Código (cpp) [Seleccionar]

void** RedimPreserve( void** __pp_vector , size_t _szt_now, size_t _szt_new )
{
   void            **__pp_back     = __pp_vector;
   void            **__new_ptr     = NULL;

   if (_szt_now==_szt_new )
       return __pp_vector;

   if ( _szt_new>0 ) {
       __new_ptr       = new void*[_szt_new];
       if ( _szt_now>0 && __new_ptr!=NULL && __pp_back!=NULL  )
           if ( _szt_now>_szt_new )
               memcpy          ( __new_ptr , __pp_back , _szt_new*sizeof(void*) );
           else
               memcpy          ( __new_ptr , __pp_back , _szt_now*sizeof(void*) );
   } else
       __new_ptr       = NULL;

   if ( __pp_back!=NULL )
       delete[]        __pp_back;

   return __new_ptr;
}


O de esta manera:

Código (cpp) [Seleccionar]

void ** RedimPreserve(void ** buff, size_t currentSize, size_t newSize)
{
   void ** currentBuff = buff;
   void ** temp = NULL;

if (currentSize == newSize)
return buff;

if (newSize > 0)
{
temp = new void*[newSize];
if (currentSize > 0 && temp != NULL && currentBuff != NULL)
if (currentSize > newSize)
memcpy(temp, currentBuff, newSize * sizeof(void*));
else
memcpy(temp, currentBuff, currentSize * sizeof(void*));
}
else
temp = NULL;

if (buff != NULL)
delete[] buff;

return temp;
}


Programar es un arte, y para un programador es un deber escribir buen código y que sea legible por otros.

Saludos.

d(-_-)b

Max 400; caracteres restantes: 366

BlackZeroX

#12
No me gusta declarar variables sin tener prefijos que NO me indiquen que tipo de variables son... es decir me guio en la nomeclatura hungara que de hecho estan hay por algo, es decir, mantenimiento de codigo a corto, media y largo plazo.

Digamoslo de esta manera:

Tienes 40 declaraciones de variables en un proceso X y varias lineas en tu proceso, si les pongo solo nombres sin que digan mucho ( tipo y/o clase ), y se lo doy a otro programador, este ultimo para que modificara solo 3 lineas, el pobre tendria que irse hasta donde estan declaradas las varibales para saber de que tipo son, y tambien para saber si se estan tratando variables tipo <Puntero>, <Puntero a Puntero> o en un caso mas raro saber si son <Punteros a Punteros a Puntero>, seria algo muy tedioso esto la vdd.

temp, Current, etc y si se desea hacer un cast entre tipos distintos, pues tendria el programador que estar transladandose a zonas que no tendria que transladarse a cada instante.

__pp_ <.. Puntero a puntero algunos solo hacen un    pNombreVariable...  yo le pongo los "_" solo para separar esta nomeclatura ( aun que estoy pensando solo realizar esto para los punteros de cualquier tipo... )

_tipo_nombre     otros ->  tipoNombre     ( Como dije estoy pensando en quitar los _ y dejarselo solo a los punteros... )

un ejemplo de lo que digo:

Código (cpp) [Seleccionar]


    if (_szt_now==_szt_new )
        return __pp_vector;

    if ( _szt_new>0 ) {
        __new_ptr       = new void*[_szt_new];
        if ( _szt_now>0 && __new_ptr!=NULL && __pp_back!=NULL  )
            if ( _szt_now>_szt_new )
                memcpy          ( __new_ptr , __pp_back , _szt_new*sizeof(void*) );
            else
                memcpy          ( __new_ptr , __pp_back , _szt_now*sizeof(void*) );
    } else
        __new_ptr       = NULL;

    if ( __pp_back!=NULL )
        delete[]        __pp_back;

    return __new_ptr;



y tu codigo:

Código (cpp) [Seleccionar]


if (currentSize == newSize) 
return buff;

if (newSize > 0)
{
temp = new void*[newSize];
if (currentSize > 0 && temp != NULL && currentBuff != NULL)
if (currentSize > newSize)
memcpy(temp, currentBuff, newSize * sizeof(void*));
else
memcpy(temp, currentBuff, currentSize * sizeof(void*));
}
else
temp = NULL;

if (buff != NULL)
delete[] buff;

return temp;



Ahora dime de que tipo son cada variable... solo lo sabrias si analizas el codigo pero eso conlleva tiempo... en mi caso si sabes que significan cada prefijo sabes que tipo son sin mayor problema.

otro ejemplo seria detectar errores entre comparaciones de Enteros con signo y enteros sin signo y asi detectar con tan solo ver las variables donde radica el error.

Ej:

Código (cpp) [Seleccionar]


//Suponiendo que las variables estan perdidas en alguna parte del codigo... pero las variables tienen prefijos...
dwVar  = -1;   // _dw_Var <--- yo lo haria asi pero creo que si quitare los "_"...
//Tendriamos que verificar que dwvar no sea menor a 0 ya que udwvar no acepta numeros negativos... aun que tiene sus equivalencias.
udwvar = dwvar;  //  Se tendria que hacer un casting...   ( -1 == -2147483648 )



si no tuviera prefijos...

Código (cpp) [Seleccionar]


//Suponiendo que las variables estan perdidas en alguna parte del codigo... pero las variables tienen prefijos...
// De que tipo es?... vamos a tener que buscar las desgraciadas variables... y esperemos que esten en donde se deberian declarar, si no tendremos que buscar en todo el codigo ¬¬".
Numero1  = -1;
Numero2 = Numero1; //<--- Si aqui genera un error, y no sabemos porque, seguro haremos un casting... pero las variables pueden albergar la misma cantidad? es decir pesa lo mismo en memoria? o tenemos que cambiar el tipo de la variable para que soporte Numero2 a Numero1 y no se puedan bits/bytes(segun sea el caso)?.



Los codigo de los sitemas Operativos y/o programas variados tienen nomeclaturas similares y no manejan en muchos casos el tipo de declaraciones que aqui Todos han mencionado (Con excepciones claro). seguramente cada empresa de software maneja y/o define una nomeclatura "X" aun que otras pueden usar la nomeclatura recomendada y que mas se usa.

Como has dicho Programar es un arte y debe ser de facil interpretacion sea cual sea el caso...

Nota: A mi nomeclatura solo le he agregado "_" para separar nombre de tipos, y no morir en el intento, aun que no es la misma nomeclatura que se usa en las estructuras y demas debido a los "_" se comprende.

Dulces Lunas!¡.
The Dark Shadow is my passion.

Khronos14

Vale, en lo de los tipos de datos tienes razón. De hecho para proyectos grandes, yo también lo hago. En el código que puse tienes 5 variables: newSize, currentSize, buff, currentBuff y temp. Creo que leyendo las variables sabes de que tipo son, excepto temp, el resto no tienen problemas.

A lo que nos referimos con tu código es al uso de __ para nombrar una variable, el uso de tabulaciones para pasar los parámetros a una función, a juntar los operadores con las variables (no lo soporto xD), etc..

Saludos.

BlackZeroX

#14
Cita de: Khronos14 en 14 Julio 2011, 00:58 AM

A lo que nos referimos con tu código es al uso de __ para nombrar una variable, el uso de tabulaciones para pasar los parámetros a una función, a juntar los operadores con las variables (no lo soporto xD), etc..


Si bueno los _ como ya dije los usare para punteros de esa manera no los mesclare con el prefijo que designa al tipo, esto si no lo cmabiare, lo de las tabulaciones loq ue yaho yo es tener una linea imaginaria que me permita ordenar las asignaciones y no me genere personalmente peresa visual.

Código (cpp) [Seleccionar]


asdasd = asd;
asds=asd;
asdsadasdsad=sd
asdsd=sad;
asds=a;
d=s;



lo que hago es ordenarlo de esta manera

Código (cpp) [Seleccionar]


asdasd          = asd;
asds            = asd;
asdsadasdsad    = sd
asdsd           = sad;
asds            = a;
d               = s;



lo hago solo por la peresa viisual que me genera al ver tanto codigo juntado, lo del memcpy fue un error... ya que lo en C lo hago de esta manera.

Código (cpp) [Seleccionar]


memcpy(
       __new_ptr ,
       __pp_back ,
       _szt_now*sizeof(void*)
       );



Pero como estoy haciendo pruebas y aun no comento nada lo dejo lineal para saber donde le faltan comentarios ( Muy breves pero explicitos ).

P.D.: Al final deje esta funcion de largo y use realloc() y malloc() para esto, dejando a new y delete para las clases.

Dulces Lunas!¡.
The Dark Shadow is my passion.

rir3760

Comentarios subjetivos sobre la notación húngara se pueden encontrar muchos, por ejemplo en la pagina de Charles Petzold. No solo eso, en libros considerados "argumentos de autoridad" hay lineamientos que abren la puerta a todo tipo de discusiones.

Por ejemplo en la biblia de C++ (el libro "The C++ Programing Language") BS recomienda, entre otras cosas, el uso de fuentes proporcionales (y para alinear el texto eso implica el uso de tabuladores en lugar de espacios).

Sin tratar de echarle mas leña al fuego a la discusión en el sentido de "¿cual es mejor?" un documento interesante es:

Making Wrong Code Look Wrong by Joel Spolsky.

Hay que tomarlo de forma objetiva, mente abierta y cada quien sacara sus propias conclusiones.


----


Un cuestionamiento objetivo en contra del uso de nombres como "__pp_back" es el siguiente.

1) Al utilizar nombres de encabezados terminados con ".h" como "<stdio.h>" el nombre de espacios utilizado es el global.

2) En C (y eso incluye las facilidades de su biblioteca estándar) los nombres con un guion bajo inicial están reservados.

Si bien el riesgo de un conflicto de nombres es bajo seria mejor evitarlo ya sea utilizando los nombres "políticamente correctos" como "<cstdio>" o bien evitando los nombres en la forma ya mencionada.


----


En cuanto al programa de BlackZeroX este se puede mejorar, esto por varias razones. La primera es que la variable "__pp_back" solo se utiliza para almacenar el valor de "__pp_vector" sin que ninguna de ellas sea modificada, por ello esa variable se puede eliminar.

De forma similar a free se puede utilizar delete, no es necesario verificar si se pasa un puntero nulo ya que el comportamiento esta garantizado (no pasa nada). Eso nos lleva a eliminar la ultima sentencia condicional.

A la variable "__new_ptr" se le da un valor inicial de NULL, eso nos lleva a eliminar (por superflua) la rama (y asignación) en:
Código (cpp) [Seleccionar]
}else
   __new_ptr = NULL;


Por ultimo un detalle que debo admitir si es subjetivo: al utilizar 0 en lugar de NULL evitamos incluir <cstdio>.

Con esos cambios (mas la nomenclatura al gusto) quedaría así:
Código (cpp) [Seleccionar]
#include <cstring>
using std::memcpy;

#include <algorithm>
using std::min;

void **RedimPreserve(void **buffer, size_t size, size_t new_size)
{
   if (size == new_size)
      return buffer;
     
   void **new_buffer = 0;
   if (new_size > 0) {
      new_buffer = new void *[new_size];
     
      if (size > 0 && buffer != 0)
         memcpy(new_buffer, buffer, min(size, new_size) * sizeof (void*));
   }
   
   delete[] buffer;
   
   return new_buffer;
}

int main()
{
   char **msg = NULL;
   
   msg = (char**) RedimPreserve((void**) msg , 00 , 10);
   msg = (char**) RedimPreserve((void**) msg , 10 , 11);
   msg = (char**) RedimPreserve((void**) msg , 11 , 10);
   msg = (char**) RedimPreserve((void**) msg , 10 , 00);
   msg = (char**) RedimPreserve((void**) msg , 00 , 13);
   msg = (char**) RedimPreserve((void**) msg , 13 , 20);
   delete[] msg;
   
   return 0;
}


Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

Karman

#16
pero siguiendo tu lógica de programación el siguiente código:

void** RedimPreserve( void** __pp_vector , size_t _szt_now, size_t _szt_new )
{
   void            **__pp_back     = __pp_vector;
   void            **__new_ptr     = NULL;

   if (_szt_now==_szt_new )
       return __pp_vector;

   if ( _szt_new>0 ) {
       __new_ptr       = new void*[_szt_new];
       if ( _szt_now>0 && __new_ptr!=NULL && __pp_back!=NULL  )
           memcpy          ( __new_ptr , __pp_back , _szt_now*sizeof(void*) );
   } else
       __new_ptr       = NULL;

   if ( __pp_back!=NULL )
       delete[]        __pp_back;

   return __new_ptr;
}


es más entendible de la forma: (size_t == unsigned integer)

void** RedimPreserve( void** __vVector , size_t uNow, size_t uNew ){
   void            **__vBack     = __vVector;
   void            **__vNewPtr     = NULL;

   if (uNow==uNew )
       return __vVector;

   if ( uNew>0 ) {
       __vNewPtr       = new void*[uNew];
       if ( uNow>0 && __vNewPtr!=NULL && __vBack!=NULL  )
           memcpy          ( __vNewPtr , __vBack , uNow*sizeof(void*) );
   } else
       __vNewPtr       = NULL;

   if ( __vBack!=NULL )
       delete[]        __vBack;

   return __vNewPtr;
}


aunque preferiría el modo:

void** RedimPreserve( void** ppvVector , size_t uNow, size_t uNew ){
   void            **ppvBack     =ppvVector;
   void            **ppvNewPtr     = NULL;

   if (uNow==uNew )
       return ppvVector;

   if ( uNew>0 ) {
       ppvNewPtr       = new void*[uNew];
       if ( uNow>0 && ppvNewPtr!=NULL && ppvBack!=NULL  )
           memcpy          ( ppvNewPtr , ppvBack , uNow*sizeof(void*) );
   } else
       ppvNewPtr       = NULL;

   if ( ppvBack!=NULL )
       delete[]        ppvBack;

   return ppvNewPtr;
}


S2

PD: Ni vi el código... solo la nomenclatura, de todas formas el código de rir3760 parece estar bien (y suele estarlo dado que le gustan este tipo de algoritmos :P)

BlackZeroX

#17
Cita de: rir3760 en 14 Julio 2011, 02:51 AM

Por ejemplo en la biblia de C++ (el libro "The C++ Programing Language") BS recomienda, entre otras cosas, el uso de fuentes proporcionales (y para alinear el texto eso implica el uso de tabuladores en lugar de espacios).
Un cuestionamiento objetivo en contra del uso de nombres como "__pp_back" es el siguiente.

1) Al utilizar nombres de encabezados terminados con ".h" como "<stdio.h>" el nombre de espacios utilizado es el global.

2) En C (y eso incluye las facilidades de su biblioteca estándar) los nombres con un guion bajo inicial están reservados.

Si bien el riesgo de un conflicto de nombres es bajo seria mejor evitarlo ya sea utilizando los nombres "políticamente correctos" como "<cstdio>" o bien evitando los nombres en la forma ya mencionada.


* Uso tabulador, no espacios...
* Ok no usare "_" para declarar variables al menos que lo requiera... ( mi idea no era "__Nombre" donde "__" indicara que son punteros mas bien "_pp_TipoNombre"...  _pp_szNombres ).
* Lo de la segunda variable y lo que presedia, ya me habia dado cuanta, pero solo me interesaba ese error, que ya esta solucionado aun asi te lo agradezco.
* Me quedo con la nomeclatura de 1 sola letra para indicar los prefijos de la variable( inclusive combinaciones como las que ha hecho Karman me gusto el prefijo "v" para tipos que puedan tomar distintos tipos de variable, inclusive me soluciono un ideal que tenia respecto a las combinaciones de los mismos ).
* NULL = (void*)0...
* Con estos dos ultimos Post muy completos me han quitado la sensacion de abrir un 2do Hilo de discucion.

P.D.: El tema ya se desvirtuo mucho, aun que ya aprendi una cosa mas!¡.

Dulces Lunas!¡.
The Dark Shadow is my passion.