2017-08-30 12 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が正しいものになります。誰もがこの望ましくない動作の原因を知っていますか?ありがとう。

+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

C++は、基盤となるハードウェアへのRAWアクセスと、迅速な開発が可能な高水準言語の間に不快な場所にあります。

一般的な原則は、あなたがこの場合に壊れたオブジェクトを移動するために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されている場合、クラスのインスタンスが2つあり、両方とも値ptrが設定されています。それらのうちの1つが破壊された場合、他のクラスの内部状態を破ることで、ptrによってアドレス指定されたメモリを解放します。

クラスが正しく実装されている場合、operator =を使用してコピーすると、共有できるものとコピーする必要があるものを理解し、正しい動作を保証できます。

生のメモリ演算子を使用してクラスを修正またはコピーすることは、この理由から未定義の動作に向いています。

関連する問題