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 будет правильным. Кто-нибудь знает, что вызывает это нежелательное поведение? Благодарю.

1 ответ

C++ находится в неудобном месте между необработанным доступом к базовому оборудованию и языком высокого уровня, который способен к быстрой разработке.

Общий принцип заключается в том, что вы не можете использовать 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;
        }
 };

Идея доступа к внутреннему состоянию не позволяет разработчику класса дать гарантии правильности.

Если бы класс Example был memcpy'ed, то было бы два экземпляра класса, причем у обоих было установлено значение ptr. Если один из них уничтожен, он освобождает память, адресуемую ptr в другом, нарушая внутреннее состояние других классов.

Когда класс хорошо реализован, копирование с использованием оператора = позволяет разработчику понять, что может быть передано и что необходимо скопировать, и может обеспечить правильное поведение.

По этой причине изменение или копирование класса с использованием необработанных операторов памяти ведет к неопределенному поведению.

Другие вопросы по тегам