RE:IMPLEMENTAR CLASES STRING Y STRINGBUFFER EN C++
Ah... esos profes...
Bueno, escencialmente una clase string sería aquella que guardara un búfer de forma dinámica, es decir, que cuando se intente agregar --o concatenar-- una subcadena, la clase tendría la capacidad de ampliarse o reducirse dinámicamente.
El stringbuffer emplea un algoritmo similar, pero con una diferencia: el empleo de "apartadores" (o ve tú a saber cómo se traduzcan): allocators. Un allocator aparta un bonche de memoria, y entonces el búfer crece y decrece a placer SIN liberar dicha memoria. Cuando se acaba su bonche, simplemente se aparta otro bloque de memoria. Cuando se reduce lo suficiente, tal que queda sin emplearse memoria equivalente a un bloque, automáticamente libera dicho bloque de memoria. Las ventajas de esto es que no andan ubicando y desubicando a cada ratito memoria, haciendo el proceso más eficiente (a costo de memoria RAM, pero puedes determinar el tamaño de bloques). Además, no te anda fragmentando la memoria a cada rato (¿haz oído hablar de la herramienta del sistema Windows: defragmentador? Bueno, lo mismo pasa en la RAM hasta que el sistema "limpia" la memoria empleada por un proceso).
En codeproject.com encontrarás una sección dedicada al tratamiento de cadenas de texto, e inclusive por ahí hay algún artículo sobre un string que se comporta como stringbuffer.
En fin, una clase string entonces debería quedar más o menos así:
class String
{
private:
char* m_pBuffer; // bufer donde residirá la cadena de texto
size_t m_nSize; // el tamaño de la misma
// aquí tendrías que mandar llamar a calloc o realloc para agrandar o disminuir
// el tamaño en memoria. Por ello, es recomendable que ubiques con malloc y
// liberes con free. Cuidado, que podrías hacer que los punteros queden
// invalidados!!!
void Reallocate(size_t nNewSize)
{
/* solo por precaución, para no perder la cadena...
char* pAuxBuffer = (char*)malloc(m_nSize);
memcpy(pAuxBuffer, m_pBuffer, m_nSize);
*/
// con realloc
m_pBuffer = (char*)realloc(m_pBuffer, nCurSize);
if (!m_pBuffer) {
// error, no hay suficiente memoria, hacer algo
}
else {
/* si tomaste la precaución comentada anteriormente:
memset(m_pBuffer, 0, nCurSize);
if (nCurSize > m_nSize) {
memcpy(m_pBuffer, pAuxBuffer, m_nSize);
} else {
memcpy(m_pBuffer, pAuxBuffer, nCurSize);
}
free(pAuxBuffer);
*/
m_nSize = nCurSize;
}
public:
String();
String(size_t nSize); // ubica memoria para nSize caracteres
String(const char* sz); //inicia a una cadena de texto
virtual ~String(); //¡¡no olvides liberar el búfer!!
//si quieres puedes incluir algunos servicios para tratar a la cadena
void Concat(String& str); //concatena una subcadena
void Reverse(); //vuelve del reverso los caracteres de la cadena
bool SubString(String str); //determina si str se encuentra en el búfer
void Trim(); //borra los espacios en blanco.
// y todos los que se te ocurran.
// regresa una cadena como array de caracteres estilo C, la puedes mandar
// llamar desde el operador const char*().
const char* CStr() {
if (m_pBuffer)
return m_pBuffer;
else
return ""; //algo sucio... quizás habría que buscar una mejor forma, pero bueno...
}
// lo importante viene en esta función, que es la que manda a reasignar la
// memoria. Sería bueno que la llamaras también desde el operador de
// asignación, operator=.
bool Assign(const char* sz)
{
size_t nCurSize = strlen(sz);
if (m_nSize != nCurSize) {
Reallocate(nCurSize);
}
strcpy(m_pBuffer, sz);
}
};
Una clase StringBuffer sería parecida, pero Reallocate se mandaría llamar sólo cuando se te acabe el bloque de memoria. Unos pequeños calculillos extra en la función Assign y una variable para que lleves cuántos bytes del bloque de memoria te quedan. Si cuando vas a hacer la asignación ya no te queda suficiente memoria (la cantidad a asignar es mayor), llamas Reallocate.
En fin, espero haberte ayudado en lugar de haberte confundido. Tanto choro ya hasta me nubló la mente.
Saludos.