2015-10-31 7 views
0

Кто-то знает, почему синтаксис последнего для вызова, оператор Dog :: operator new вызывает конструктор по умолчанию после выполнения выделения, заканчивая вызовом 2-х конструкторов?оператор-член класса new, вызывающий конструктор дважды

Я хочу знать, если я делаю что-то не так, и как я могу сделать:

Dog *ptr = new("arg") Dog();

без вызова 2 конструкторов. и без использования каких-либо трюков, например, проверка конструктора по умолчанию, если объект уже сконструирован. Вот код:

class Dog 
{ 
public: 

    Dog() // default 
    { 
     std::cout << "default Dog constructor [" << this << "]" << std::endl; 
    } 

    Dog(int x) // int argument 
    { 
     std::cout << "dog constructor int " << x << "[" << this << "]" << std::endl; 
    } 

    Dog(const std::string& word) // std::string argument 
    { 
     std::cout << "dog constructor std::string: " << word << " ["<< this << "]" << std::endl; 
    } 

    Dog(std::string &&word) // rvalue string argument 
    { 
     std::cout << "dog constructor std::string&& rvalue: " << word << " [" << this << "]" << std::endl; 
    } 



    // custom operator new 
    static void *operator new(std::size_t size) noexcept // for default constructor 
    { 
     Dog *ptr = (Dog*)malloc(size); // allocate memory 
     if (ptr) // if allocate ok 
     { 
      ::new(ptr) Dog(); // call default constructor on object in memory 
      return ptr; // returns 
     } 
     else 
      return nullptr; 

    } 

    template<class T> 
    static void * operator new(std::size_t size, T&& value) noexcept // for argument constructor 
    { 
     Dog *ptr = (Dog*) malloc(size); // allocate the memory 
     if (ptr) 
     { 
      ::new (ptr) Dog(std::forward<T>(value)); // pass the argument exactly as was passed to operator new, 
                 // using perfect forwarding 
      return ptr; 
     } 
     else 
      return nullptr; 

    } 


    ~Dog() { std::cout << "destructor " << std::endl; } 
}; 



int main(void) 
{ 




    Dog *d = (Dog*) Dog::operator new(sizeof(Dog), "Const Char * Argument"); // argument version 
    Dog *d2 = (Dog*)Dog::operator new(sizeof(Dog)); // default constructor argument 

    //1 this works as expected, do what you specified in the member operator new, everything goes normal. 




    Dog *d3 = new Dog(); // default constructor 
    Dog *d4 = new("Const Char * Argument") Dog(); // argument constructor 

    // this is shorter, goes into your member operator new, BUT when it returns to this scope, 
    // call the default constructor for *d3, and for *d4 too. 

    // so this ends up calling constructors twice for both objects. 



} 

Итак, я смешивала выделение со строительством, нет никаких оснований для этого, что здесь, может быть, есть некоторые используют для этого в операторе новый [], чтобы построить массив с contructor, кроме конструктора по умолчанию.

Но самый лучший способ, чтобы определить эти члены операторы:

class Dog { 
public: 
// ....... 

     // custom operator new 
    static void *operator new(std::size_t size) noexcept // for default constructor 
    { 
     void *memory = malloc(size); // allocate memory 
     if (memory) // if allocate ok 
     { 
      return memory; // returns 
     } 
     else 
      return nullptr; 

    } 

    static void *operator new[](std::size_t size) noexcept 
    { 
     void *memory = malloc(size); // allocate memory 
     if (memory) // if allocate ok 
     { 
      return memory; // returns 
     } 
     else 
      return nullptr; 
    } 

    static void operator delete(void *block) noexcept 
    { 
     free(block); 
    } 

    static void operator delete[](void *block) noexcept 
    { 
     free(block); 
    } 

    ~Dog() { std::cout << "destructor " << std::endl; } 
}; 



int main(void) 
{ 
    // now we can use new operator normaly without complications 
    Dog *d1 = new Dog[10]; // default constructor on all objects 

    Dog *d2 = new Dog("const char * argument"); // call std::string&& constructor 

    delete[] d1; 
    delete d2; 





} 
+3

Почему вы используете 'malloc' в коде на C++? –

ответ

3

Используя (ключевое слово) новый: Он вызывает оператор выделения новых и вызывает конструктор (!).

Примечание: при предоставлении оператора new вы также должны предоставить оператор delete (в вашем случае это будет бесплатно). Кроме того, не забывайте о версиях массива.

+0

возобновление, чтобы правильно использовать оператор-член new для «Dog», я должен использовать первый синтаксис. Собака * ptr = (Собака *) Собака :: оператор new (sizeof (Dog), arg); –

+0

@ RafaelMoura Не смешивайте распределение и конструкцию. –

+1

О, я понял, его не следует вызывать конструктором из оператора-члена new, но пусть по умолчанию его можно назвать и будет работать нормально. Благодарю. –