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++ 程序中使用 malloc
和 free
之前,我想重申一下,这只是一个测试程序,即使使用 operator new
& operator delete
。但我的问题仍然是:
- 即使没有使用
malloc or operator new
创建 X 的对象,我们如何访问 class X 的变量 x?
- 显然
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
进行分配,则无法保证返回的指针来自内部调用的 malloc
、realloc
或 calloc
,只有将指针传递给 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
变量),变量会在那里,只有构造函数不会被调用,所以它的值不会被设置为零。如果您 运行 程序时它最初为零,那只是巧合。
如果您通过调用 free()
取消分配使用 new
创建的对象,您将陷入未定义的行为。同样,如果你用 delete
释放一个 malloc()
的对象,你有未定义的行为。无论你做什么,都不要将两者混为一谈。
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 & free
与 new & delete
混淆,因为它会创建 UB 而不会发生这样的结果。
我先 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++ 程序中使用 malloc
和 free
之前,我想重申一下,这只是一个测试程序,即使使用 operator new
& operator delete
。但我的问题仍然是:
- 即使没有使用
malloc or operator new
创建 X 的对象,我们如何访问 class X 的变量 x? - 显然
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
进行分配,则无法保证返回的指针来自内部调用的 malloc
、realloc
或 calloc
,只有将指针传递给 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
变量),变量会在那里,只有构造函数不会被调用,所以它的值不会被设置为零。如果您 运行 程序时它最初为零,那只是巧合。
如果您通过调用
free()
取消分配使用new
创建的对象,您将陷入未定义的行为。同样,如果你用delete
释放一个malloc()
的对象,你有未定义的行为。无论你做什么,都不要将两者混为一谈。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 & free
与 new & delete
混淆,因为它会创建 UB 而不会发生这样的结果。