2017-08-30 5 views
-1

je jouais des modèles autour de quand je suis surpris que le code ci-dessous ne fonctionne pas comme prévu:C++: Copier des objets avec memmove et Malloc

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

template <class Object> 
class CreatorTWO { 
public: 
    CreatorTWO (void) {} 
    ~CreatorTWO (void) throw() {} 
    template <typename... Object_Params> 
    Object* create (const Object_Params&... params_) { 
    Object _temp_obj = Object(params_...); 
    size_t _obj_bytes = sizeof (_temp_obj); 
    void * _mem_block = std::malloc (_obj_bytes); 
    std::memmove(_mem_block,&_temp_obj,_obj_bytes); 
    //The line below prints the dereferenced object before it is returned: 
    std::cout << *(static_cast <Object*> (_mem_block)) << '\n'; 
    return static_cast <Object*> (_mem_block); 
    } 
}; 

int main (int argc, char* argv[]) { 
    CreatorTWO <std::string> _c2; 
    std::string* _strp = _c2.create("Hello"); 
    std::cout << *_strp << '\n'; 
    std::free (_strp); 
    return 0; 
} 

Le code ci-dessus est censé créer un objet avec nombre variable des paramètres qui lui sont transmis. Cependant, quand j'ai créé une instance avec std :: string, passer un argument de "Hello" devrait me donner un pointeur sur une chaîne contenant "Hello". Cependant, ce n'est pas le cas. Si vous exécutez le code ci-dessus, les valeurs pré et post sont différentes, le pré étant le bon. Est-ce que quelqu'un sait ce qui provoque ce comportement indésirable? Merci.

+0

N'utilisez pas 'malloc()' avec C++. – user0042

+3

Vous ne pouvez pas créer un objet avec 'malloc' ou le déplacer avec' memcpy' (ou des fonctions similaires) sauf si cet objet est un [type POD] (http://en.cppreference.com/w/cpp/concept/PODType) . Pour en savoir plus: https://stackoverflow.com/questions/146452/what-are-pod-types-in-c 'std :: string' n'est définitivement pas un type POD. –

+0

Tout simplement parce que vous avez piraté un allocateur personnalisé, cela ne signifie pas que vous pouvez ignorer l'appel du desturcteur. – StoryTeller

Répondre

1

C++ se trouve dans un endroit inconfortable entre l'accès brut au matériel sous-jacent, et un langage de haut niveau qui est capable de développement rapide.

Le principe général est que vous ne pouvez pas utiliser memcpy pour déplacer un objet que vous avez cassé dans ce cas.

Lorsque vous créez une classe.

class Example { 
    protected: 
     char * ptr; 
     size_t len; 
    public: 
     Example(const char * str) { 
      len = strlen(str); 
      ptr = new char[ len + 1]; 
     } 
     virtual ~Example() { 
      delete [] ptr; 
     } 
     Example & operator=(const Example & rhs) { 
      if(&rhs != this) { 
       delete [] ptr; 
       len = rhs.len(); 
       ptr = new char[ len + 1 ]; 
       strcpy(ptr, rhs.ptr); 
      } 
     } 
     Example(const Example & src) { 
      len = src.len; 
      ptr = new char[ len + 1]; 
      strcpy(ptr, src.ptr); 
     } 
     Example() { 
      ptr = new char[1]; 
      ptr[0] = '\0'; 
      len = 0; 
     } 
}; 

L'idée d'accéder à l'état interne arrête le concepteur de la classe d'être en mesure de donner des garanties d'exactitude.

Si l'exemple de classe avait été mémcpyé, alors il y aurait deux instances de la classe, les deux ayant la valeur ptr définie. Si l'un d'eux est détruit, alors il libère la mémoire adressée par ptr dans l'autre, brisant l'état interne des autres classes. Quand une classe a été bien implémentée, la copie en utilisant l'opérateur = permet au concepteur de comprendre ce qui peut être partagé et ce qui doit être copié, et peut garantir un comportement correct. En modifiant ou en copiant une classe en utilisant des opérateurs de mémoire brute, on se dirige vers un comportement indéfini pour cette raison.