【问题标题】:class member operator new, calling constructor twice类成员运算符new,两次调用构造函数
【发布时间】:2016-01-31 18:41:36
【问题描述】:

有人知道为什么调用的后一种语法 Dog::operator new 在分配后调用默认构造函数,最终调用了 2 个构造函数?

我想知道我是否做错了什么,我该怎么做:

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.



}

所以,我将分配与构造混合在一起,这里没有理由这样做,也许在 operator new[] 中使用它来使用默认构造函数以外的构造函数构造数组。

但定义这些成员运算符的最佳方式是:

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;





}

【问题讨论】:

  • 为什么在 C++ 代码中使用malloc

标签: c++ constructor new-operator member-functions


【解决方案1】:

使用(关键字)new:它调用分配运算符 new 并(!)调用构造函数。

注意:在提供 operator new 时,您也应该提供 operator delete(在您的情况下,它会调用 free)。另外,不要忘记数组版本。

【讨论】:

  • 恢复,为了正确使用“Dog”的成员运算符new,我必须使用第一种语法。 Dog ptr = (Dog) Dog::operator new(sizeof(Dog), arg);
  • @RafaelMoura 不要混合分配和构造。
  • 哦,我明白了,它不应该从成员运算符 new 中调用构造函数,而是让默认方式调用它并且可以正常工作。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-02
  • 2017-07-29
  • 1970-01-01
  • 2011-03-18
  • 2014-06-16
  • 1970-01-01
相关资源
最近更新 更多