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



我将首先用c++发布我的测试程序:

#include <iostream>
using namespace std;
class X
{
     int x;
     public:
     X()
     {
       cout<<"constructingn";
       x=0;
     }
     int& getx()
     {
       return x;
     }
     ~X()
     {
       cout<<"destroyingn";
     }
};
int main()
{
     X* p=(X*)malloc(sizeof(X));
     ++p->getx();
     p->getx()*=5;
     cout<<p->getx();
     free(p);
     return 0;
}
输出:

5

现在,在有人抱怨为什么我使用malloc &free在c++程序中,我想重申,它只是一个测试程序,即使使用operator new &operator delete。但我的问题仍然是:

  1. 即使没有使用malloc or operator new创建X的对象,我们如何访问类X的变量X ?
  2. 显然free & operator delete也不会破坏对象并执行仅仅的分配。如果我用new创建一个对象,但使用operator delete or free而不是delete,会发生什么?我的对象还会在那里吗?它还能用吗?
  1. 如果您通过调用free()来释放使用new创建的对象,您将陷入未定义行为。同样,如果用delete释放一个malloc() 'ed对象,就会有未定义的行为。无论你做什么,永远不要把这两者混在一起。

  2. malloc()的语义与new不同:malloc()只是分配内存,它不调用构造函数。new执行分配,并调用相应的构造函数。

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

你可以在c++中使用malloc()来支持一个真正的c++对象,但是你必须自己做构造函数/析构函数调用:

//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

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


对于你关于p->getx()为什么编译的问题。这可以归结为代码中的这个转换:

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

在这里,程序员明确地告诉编译器:"我知道我给你的值看起来不像指向X的指针,但我告诉你它是。"所以,愚蠢的编译器,不要再提类型不匹配了,把它当作指向X的指针,因为我,人类,你的上帝,告诉你了!"

编译器能做什么?它关闭了类型不匹配,并将指针视为指向X的指针,正如您告诉它的那样。如果那不对,那是你的问题。也许程序会正常运行,也许它会崩溃,也许它会悄悄地破坏数据,也许会出现一个粉红色的大象。你的编译器不会在意的。它唯一关心的是它实现了你的愿望。编译器可以非常顺从。

回答问题的这一部分:"如果我用new创建对象,但使用delete或free操作符而不是delete,会发生什么?"我的对象还会在那里吗?它还能用吗?"

malloc分配和用delete释放是未定义的行为。在调用对象的析构函数后,不能保证实现将使用C的free

反之亦然。如果使用new进行分配,则不能保证返回的指针来自内部调用的mallocrealloccalloc,只有在将指针传递给free是安全的情况下才可以。

即使它可以工作,它也可能破坏程序和/或泄漏资源,因为您将跳过对象的构造函数或析构函数。

编辑:

你说"显然免费&操作符删除也不破坏对象,只执行错位。嗯,这是错误的。delete将调用对象的析构函数,因此它将先销毁,然后再释放。

至于评论中澄清的问题,对于"为什么你仍然可以访问x",好吧,malloc将分配对象占用的全部空间(在你的情况下,我相信只是x变量),变量将在那里,只有构造函数不会被调用,所以,它的值不会被设置为零。如果在运行程序时初始值为0,那么这只是一个巧合。

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

#include <iostream>
#include <vector>
using namespace std;
class X
{
    int x;
    vector<int> v;
    public:
    X()
    {
      cout<<"constructingn";
      x=0;
      v.push_back(1);
      v.push_back(2);
    }
    int& getx()
    {
      return x;
    }
    vector<int>& getv()
    {
      return v;
    }
    ~X()
    {
      cout<<"destroyingn";
    }
};
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<<"nexecutedn";
    operator delete(p);
    return 0;
}
/* Output :-
   5
   executed
*/ 

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

constructing
5
1 2 
executed
destroying

现在你的代码给出了正确的&好结果!刚果!

对于你的第二个问题,永远不要把malloc & freenew & delete混在一起,因为它会创建UB,而不会产生这样的结果。

相关内容

  • 没有找到相关文章

最新更新