See the program below:
#include <cstdio>
#include <cstring>
#include <iostream>
class Chaine {
 private:
  char* _donnees;
  unsigned int _taille;
 public:
  Chaine();
  Chaine(const char*);
  ~Chaine();
  unsigned int taille() const;
};
Chaine::Chaine():_taille(0) {
  _donnees=new char[1];
  _donnees[0]='\0';
}
Chaine::Chaine(const char *s) { 
  _taille = std::strlen(s);
  _donnees = new char[_taille + 1];
  std::strcpy(_donnees, s);
  std::printf("%s(%d): %s\n", __FILE__, __LINE__, __func__);
}
Chaine::~Chaine() {
  if(*_donnees == 0){
      std::printf("_donnees points to freed block\n");
  }
  else{
      std::printf("_donnees points to freed block\n");
      delete[] _donnees;
      _donnees=NULL;
  }
  std::printf("%s(%d): %s\n", __FILE__, __LINE__, __func__);
}
unsigned int Chaine::taille() const{
    return _taille;
}
int main() {
    Chaine s1("une chaine"); 
    Chaine *s2 = new Chaine("s3");
    Chaine s3 = s1; 
    delete s2;
}
I compiled using g++ -Wall -o test test.cpp then run valgrind --leak-check=full ./test and got messages below:
/test
==5638== Memcheck, a memory error detector
==5638== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==5638== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==5638== Command: ./test
==5638== 
test.cpp(29): Chaine
test.cpp(29): Chaine
_donnees points to freed block
test.cpp(41): ~Chaine
_donnees points to freed block
test.cpp(41): ~Chaine
==5638== Invalid read of size 1
==5638==    at 0x804886D: Chaine::~Chaine() (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638==    by 0x804895F: main (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638==  Address 0x4353028 is 0 bytes inside a block of size 11 free'd
==5638==    at 0x402B598: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5638==    by 0x80488A3: Chaine::~Chaine() (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638==    by 0x8048953: main (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638== 
_donnees points to freed block
==5638== Invalid free() / delete / delete[] / realloc()
==5638==    at 0x402B598: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5638==    by 0x80488A3: Chaine::~Chaine() (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638==    by 0x804895F: main (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638==  Address 0x4353028 is 0 bytes inside a block of size 11 free'd
==5638==    at 0x402B598: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5638==    by 0x80488A3: Chaine::~Chaine() (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638==    by 0x8048953: main (in /home/qliang/Documents/ENSEIRB/cpp/td2/chaine2/test)
==5638== 
test.cpp(41): ~Chaine
==5638== 
==5638== HEAP SUMMARY:
==5638==     in use at exit: 0 bytes in 0 blocks
==5638==   total heap usage: 3 allocs, 4 frees, 22 bytes allocated
==5638== 
==5638== All heap blocks were freed -- no leaks are possible
==5638== 
==5638== For counts of detected and suppressed errors, rerun with: -v
==5638== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
I the deconstructor, I want to check if the memory _donnees points to has been freed to avoid re-free. One solution(maybe bad solution) is to declare a static integer in deconstructor, like
Chaine::~Chaine() {
  static int num_free = 0;
  if(num_free == 1){
      std::printf("_donnees points to freed block\n");
  }
  else{
      std::printf("_donnees points to freed block\n");
      delete[] _donnees;
      num_free = 1;
      _donnees=NULL;
  }
  std::printf("%s(%d): %s\n", __FILE__, __LINE__, __func__);
}
But I want to know if there is some way like *_donnees == NULL to check if the block of memory is freed or not.
And, why valgrind displays messages:
==5638== Invalid read of size 1
==5638== Invalid free() / delete / delete[] / realloc()
and why each of these messages just show once?
 
    