Como limpar um struct

1. Como limpar um struct

William Lima
willdoidao

(usa Ubuntu)

Enviado em 25/09/2014 - 20:39h

Pessoal,
Preciso limpar todos os valores armazenados em um struct, por exemplo:

#include <cstring>
#include <iostream>
#include <string>

struct Strings
{
std::string s1;
std::string s2;
u16 valores;
};

int main(int argc, char *argv[])
{
Strings myStrings;
myStrings.s1 = "one";

std::cout << "s1: " << myStrings.s1.length() << std::endl;

std::memset(&myStrings, 0, sizeof(myStrings));

std::cout << "s1: " << myStrings.s1.length() << std::endl;

return 0;
}


Só consegui até agora o retorno:


[[email protected] Área de trabalho]$ vim arquivo.cpp
[[email protected] Área de trabalho]$ g++ arquivo.cpp -o vamos
[[email protected] Área de trabalho]$ ./vamos
s1: 3
Falha de segmentação (imagem do núcleo gravada)
[[email protected] Área de trabalho]



Alguma ideia de como limpar esse struct?




  


2. Re: Como limpar um struct

Luis R. C. Silva
luisrcs

(usa Linux Mint)

Enviado em 26/09/2014 - 07:05h

Se você já criou a variável, ele não pode ser destruída. Só objetos são destruíveis. O que pode fazer é criar uma função que zere os valores da variável criada, mas não destruir variáveis, mesmo porque elas já ocupam um espaço estático na memória.


3. Re: Como limpar um struct

Paulo
paulo1205

(usa Ubuntu)

Enviado em 26/09/2014 - 17:50h

Sobrescrever o valor de uma estrutura com bytes nulos só é aceitável quando seus campos internos são tipos nativos da linguagem (incluindo ponteiros) ou arrays desses tipos nativos. Objetos de classes complexas, como std::string, definitivamente inviabilizam essa prática comum do C.

Mesmo assim, e mesmo em C, é preciso ter cuidado quando a estrutura tem campos que são ponteiros, pois o simples fato de sobrescrever um ponteiro com um valor nulo não quer dizer que a memória para onde apontava antes será devidamente liberada.

O seu problema em particular é que o tipo std::string tem vários campos internos que são usados para implementar a funcionalidade de um string que se autoadministra, podendo mudar de tamanho dinamicamente (incluindo a alocação inicial e a desalocação final) e economizar memória através de compartilhamento de bytes comuns com outros strings que sejam copiados a partir dele. Quando você sobrescreve esses campos internos com valores arbitrários, interfere de modo completamente inesperado -- e negativo -- com a funcionalidade natural desses objetos.

Por qual motivo você está querendo sobrescrever seus strings com bytes nulos? Impedir leitura de informação residual depois que ela não for mais necessária?

Se for esse último caso, você terá de fazer de outra maneira. Um jeito seria embutir um destrutor na sua classe (em C++, classes e estruturas são praticamente sinônimos, mudando apenas o tipo de acesso default ao membros). Por exemplo:

struct Strings
{
std::string s1, s2;
u16 valores;

// Função de limpeza, para substituir o ‘memset(&objeto, 0, sizeof objeto)’.
// Você pode chamar essa função a qualquer momento.
void clear(){
valores=0;

s1.clear();
s2.clear();
/*
// Ou, se você quiser ser um pouco mais paranoico, o seguinte:
for(i=0; i<s1.length(); i++)
s1=0;
s1.clear();
for(i=0; i<s2.length(); i++)
s2[i]=0;
s2.clear();
*/
}

// Destrutor, invocado automaticamente quando o objeto deixa de existir.
~Strings(){
clear();
}
};


Alternativamente, você poderia estender o tipo [i]std::string
, trazendo um pouco da limpeza paranoica para a própria gestão do string.

class ParanoidString: public std::string {
public:
void clear(){
for(i=0; i<this->length(); i++)
(*this)=0;
std::string::clear();
}

~ParanoidString(){
clear();
}
};

struct Strings
{
ParanoidString s1, s2;
u16 valores;

// Função de limpeza, para substituir o ‘memset(&objeto, 0, sizeof objeto)’.
// Você pode chamar essa função a qualquer momento.
void clear(){
valores=0;
s1.clear();
s2.clear();
}

// Destrutor, invocado automaticamente quando o objeto deixa de existir.
~Strings(){
valores=0;
// Nem preciso limpar explicitamente s1 e s2: seus próprios destrutores farão isso.
}
};


Note, porém, que nenhum dos exemplos acima cobre a possibilidade de ter de limpar resíduos caso um dos campos [i]string
seja modificado mais de uma vez ao longo da vida do objeto, principalmente se ocorrer redução de tamanho ou operação que envolva (re)cópia dos caracteres internos. Se você quiser algo do tipo, provavelmente terá de aumentar a quantidade de funções dentro de ParanoidString, ou criar uma classe totalmente nova.