c++ malloc 和自由对象的创建和删除

c++ malloc and free object creation and deletion

我先 post 我的 C++ 测试程序 :

#include <iostream>
using namespace std;

class X
{
     int x;
     public:
     X()
     {
       cout<<"constructing\n";
       x=0;
     }
     int& getx()
     {
       return x;
     }
     ~X()
     {
       cout<<"destroying\n";
     }
};
int main()
{
     X* p=(X*)malloc(sizeof(X));
     ++p->getx();
     p->getx()*=5;
     cout<<p->getx();
     free(p);
     return 0;
}

输出:

5

现在,在有人抱怨为什么我在 C++ 程序中使用 mallocfree 之前,我想重申一下,这只是一个测试程序,即使使用 operator new & operator delete。但我的问题仍然是:

  1. 即使没有使用 malloc or operator new 创建 X 的对象,我们如何访问 class X 的变量 x?
  2. 显然 free & operator delete 也不要破坏对象并仅执行分配。如果我使用 new 创建对象但使用 operator delete or free 而不是 delete 会发生什么情况?我的物品还会在那里吗?它还能用吗?

回答这部分问题:"What would happen if I create an object with new but use operator delete or free instead of delete ? Would my object still be there & will it be still usable ?"

使用 malloc 分配并使用 delete 释放是未定义的行为。没有 gua运行tee 实现将在调用对象的析构函数后使用 C 的 free

反之亦然。如果您使用 new 进行分配,则无法保证返回的指针来自内部调用的 mallocrealloccalloc,只有将指针传递给 free.

是安全的

即使有效,它也可能会破坏程序 and/or 泄漏资源,因为您将跳过对象的构造函数或析构函数。

编辑:

你说"Clearly free & operator delete also do not destroy the objects and perform mere dallocations."嗯,那是错误的。 delete 会调用对象的析构函数,所以会先销毁再释放。

至于评论中澄清的问题,对于 "why can you still access x",嗯,malloc 将分配对象占用的全部 space(在您的情况下,我相信只是 x 变量),变量会在那里,只有构造函数不会被调用,所以它的值不会被设置为零。如果您 运行 程序时它最初为零,那只是巧合。

  1. 如果您通过调用 free() 取消分配使用 new 创建的对象,您将陷入未定义的行为。同样,如果你用 delete 释放一个 malloc() 的对象,你有未定义的行为。无论你做什么,都不要将两者混为一谈。

  2. malloc()new 有不同的语义:malloc() 只是分配内存,它不调用构造函数。 new 进行分配,并调用适当的构造函数。

    同样,free()delete之间也有类似的区别:delete在释放内存之前调用析构函数,free()不会。

您可以在 C++ 中使用 malloc() 来支持真正的 C++ 对象,但您必须自己执行 constructor/destructor 调用:

//The placement-new below needs this:
#include <new>

//This is what new does:
char* temp = (char*)malloc(sizeof(Foo));    //allocation only
Foo* foo = new(temp) Foo();    //placement-new: construction only

//This is what delete does:
foo->~Foo();    //destruction only
free((void*)foo);    //deallocation only

请注意,第二行中的 placement-new 语法是在 C++ 中显式调用构造函数的唯一方法。可以像任何其他成员一样显式调用析构函数。这种不对称的原因是对象在销毁前确实是一个有效对象,而在构造前不是这样。


关于 p->getx() 为什么编译的问题。这归结为您代码中的这个小演员:

X* p=(X*)malloc(sizeof(X));
      ^
      |
this little cast

在这里,你,程序员,明确地告诉编译器:"I know that the value I'm giving you does not look like a pointer to X, but I tell you that it is. So, stupid compiler, just shut up about the type mismatch, and treat it as a pointer to X anyway, because I, the human, your god, told you so!"

那么你的编译器能做什么?它关闭了类型不匹配的问题,并将指针视为指向 X 的指针,正如您所说的那样。如果那是错误的,那是你的问题。也许这个程序无论如何都会 运行 正常,也许它崩溃了,也许它默默地破坏了数据,也许一头粉红色的大象出现了。你的编译器不会在意。唯一关心的是它是否符合您的意愿。编译器可以很听话

看了这么多的观点,我自己写了一个程序来解释你的问题。见下文:-

#include <iostream>
#include <vector>
using namespace std;

class X
{
    int x;
    vector<int> v;
    public:
    X()
    {
      cout<<"constructing\n";
      x=0;
      v.push_back(1);
      v.push_back(2);
    }
    int& getx()
    {
      return x;
    }
    vector<int>& getv()
    {
      return v;
    }
    ~X()
    {
      cout<<"destroying\n";
    }
};
int main()
{
    X* p=(X*)operator new(sizeof(X));
    ++p->getx();
    p->getx()*=5;
    cout<<p->getx()<<"\n";
    for (int x:p->getv())
    cout<<x<<" ";
    cout<<"\nexecuted\n";
    operator delete(p);
    return 0;
}
/* Output :-
   5

   executed
*/ 

看看 p 如何忽略向量 v 并选择行 executed。这是因为 vector<int>class(或更准确地说是 class template)从未由 operator new (or malloc in your case) 创建。您的程序显示了 x 的输出,因为它是原始类型而不是 class。对于 class,您需要一个构造函数,因此 operator new or malloc 不适合 classes,因此不适合输出。如果您简单地替换 operator new with new & operator delete with delete 那么输出将是 :-

constructing
5
1 2 
executed
destroying

现在您的代码给出了正确且恰当的结果!刚果 !

对于你的第二个问题,切勿将 malloc & freenew & delete 混淆,因为它会创建 UB 而不会发生这样的结果。