2017-08-30 70 views
-1

我玩弄模板的時候,我很驚訝,因爲預計下面的代碼不起作用:C++:複製對象使用的memmove()和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; 
} 

上面的代碼應該創建具有不同數目的對象的參數傳遞給它。但是,當我創建一個使用std :: string模板的實例時,傳遞一個「Hello」參數應該給我一個指向包含「Hello」的字符串的指針。然而,這種情況並非如此。如果你運行上面的代碼,pre和post的值與pre是正確的不同。有誰知道是什麼原因導致了這種不良行爲?謝謝。

+0

不要在'C++中使用'malloc()'。 – user0042

+3

除非該對象是[POD類型](http://en.cppreference.com/w/cpp/concept/PODType),否則不能用'malloc'創建對象或用'memcpy'(或類似的函數) 。進一步閱讀:https://stackoverflow.com/questions/146452/what-are-pod-types-in-c'std :: string'最明確地不是POD類型。 –

+0

僅僅因爲你破解了一個自定義分配器,並不意味着可以跳過去極化器的調用。 – StoryTeller

回答

1

下在原始訪問底層硬件,並能夠快速發展的高級語言之間的不舒服的地方++坐。

總的原則是,你不能使用memcpy移動對象,你在這種情況下,已經打破。

當你創建一個類。

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; 
     } 
}; 

訪問內部狀態的想法停止類的設計者從能夠做出正確的保證。

如果類實施例已經memcpy'ed,那麼就不會有類的兩個實例,用既具有值PTR集。如果其中一個被破壞,那麼它釋放由另一個ptr尋址的內存,打破其他類的內部狀態。

當一個類已經很好的落實,使用操作=複製使設計人員能夠明白什麼可以共享,哪些需要複製,並能確保正確的行爲。

通過使用原始內存操作符修改或複製類正在朝着未定義的行爲出於此原因。