c++重载delete操作符与析构函数冲突,编译不过

雨中鹰 2014-05-16 10:48:30
#include <iostream>
using namespace std;

class Test{
public:
Test():x(3){
cout << "ctor Test() is called!" << endl;
}
~Test(){
cout << "dtor ~Test() is called!" << endl;
}

int getX(){
return x;
}
private:
int x;
void * operator new(size_t);
void * operator new[](size_t);
void operator delete(void*);
void operator delete[](void *);
};

int main(){
Test t;
cout << t.getX() << endl;
cout << "----------------" << endl;
//t.~Test(); //如果析构函数存在编译错误 析构函数与delete不可同时存在为什么
Test *ptr = ::new Test(); //输出 3
cout << ptr->getX() << endl;
//ptr->~Test(); //如果析构函数存在编译错误
//::delete ptr; //如果析构函数存在编译错误

cout << "----------------" << endl;
Test *p = static_cast<Test*>(::operator new((size_t)sizeof(Test)));
cout << p->getX() << endl;
cout << "----------------" << endl;
::operator delete(p);

return 0;

}
为什么析构函数不可以与operator delete共存呢?
...全文
266 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
lm_whales 2014-05-18
  • 打赏
  • 举报
回复
A *a = (::operator new(sizeof(A)),new (a) A());
lm_whales 2014-05-18
  • 打赏
  • 举报
回复
引用 12 楼 menglinaoxiang 的回复:
[quote=引用 7 楼 lm_whales 的回复:] 上述代码中,标有1,2,3,4,5,如果先将4,5两行代码注释掉,编译是不通过的,原因是3,2,1有冲突,我不明白为什么这里会有冲突,如果将2注释掉就可以。 4,5也是这样的问题,如果要想编译通过,要注释掉2, 如果不重新写自己的析构函数,那不注释掉2,有5也可以正常编译 你可以拷贝一下代码编译试一下,我在vs2012下编译的
这个不需要试验 这和
void * operator new(size_t);
void * operator new[](size_t);
void operator delete(void*);
void operator delete[](void *);
无关 Test t;//这种方式定义的变量 (对象), //例如。。。函数内部局部变量,外部变量,静态变量,类的静态成员变量,等等,会自动调用析构函数。 cout << t.getX() << endl; t.~Test(); //()3这里主动调用,析构函数是错误的,因为 析构函数会自动调用。
void * operator new(size_t);
void * operator new[](size_t);
void operator delete(void*);
void operator delete[](void *);
重定义是为了更有效地利用内存,这么定义是为了定义堆对象, new 的时候,分配内存会自动调用类的operator new,而不是全局的 operator new 即 A *a =new A;//===> 不重载 相当于这么做 a = ::operator new(sizeof(A)); new (a) A(); 重载后 相当于这么做 a = A::operator new(sizeof(A)); new (a) A();// 这是重载和不重载的区别。 其他3个运算符类似。 另外 重载以后 直接调用 ::operator new 分配内存毫无意义 因为还需要显式释放 本来定义operator new就是为了不直接用 ::operator new,结果还是显式使用了 ::operator new 何必多此一举。
qq120848369 2014-05-18
  • 打赏
  • 举报
回复
引用 16 楼 menglinaoxiang 的回复:
[quote=引用 14 楼 qq120848369 的回复:] [quote=引用 13 楼 menglinaoxiang 的回复:] [quote=引用 11 楼 qq120848369 的回复:] 栈上对象离开作用域会自己析构释放内存,你不需要为它显式的调用析构函数,delete同理。 楼主想做的可能与placement new有关,可以自己百度看一下。
#include <iostream>
using namespace std;

class Test{
public:
	Test():x(3){cout << "ctor Test() is called!" << endl;	}
	~Test(){ cout << "dtor ~Test() is called!" << endl; }//(1)	
	int getX(){	return x; }
private:
	int x;
	void * operator new(size_t);
	void operator delete(void*);//(2)
};

int main(){
	Test *ptr = ::new Test(); //输出 3
	cout << ptr->getX() << endl;
	ptr->~Test(); //(4)
	::delete ptr; //(5)

	return 0;
}
可是我这样,用全局的new从堆上分配的内存,这样的情况也编译不通过,我做这个小例子本来是想不允许用户在堆上申请内存的,我上面的代码用了全局的::new与全局的::delete结果还是编译不通过,全局的new,delete与类内部的new,delete与析构函数之间有什么联系吗? 如果不重写析构函数上面的代码是可以通过的, 如果不在类中重写operator delete也是可以编译通过的,我不明白其中的关系[/quote] 楼主几个关键概念需要理解: 1,new是一个关键字,它的动作是:void* operator new(size_t) + operator new(size_t,void*ptr),既先分配一块内存,然后在内存上构造对象。 2,所以楼主代码里的::new和::delete是压根不存在的用法。 想要限制一个类在堆上创建是做不到的,虽然你可以private掉static void* operator new(size_t);和static void operator delete(void*);,这样用户调用new和delete会失败,但是用户完全可以显式指定使用::operartor new(size_t)+::operator new(size_t,void*ptr)搞定。[/quote] 版主好,::new ::delete确实是存在的,在c++ primer 中有讲到,我清楚全局的operator new是库函数,而类中重写的是操作符, 如果使用new操作符会先调用库函数operator new然后再调用类的构造函数, delete是先调用析构函数,再调用库函数operator delete。 你看看下面的代码及运行结果
#include <iostream>
using namespace std;

class Test{
public:
	Test():x(3){cout << "ctor Test() is called!" << endl;	}
	int getX(){	return x; }
private:
	int x;
	void * operator new(size_t);
	void operator delete(void*);//(2)
};

int main(){
	Test *ptr = ::new Test(); //输出 3
	cout << ptr->getX() << endl;
	ptr->~Test(); //(4)
	::delete ptr; //(5)

	cout << "----------------" << endl;
	Test *p = static_cast<Test*>(::operator new((size_t)sizeof(Test)));
	cout << p->getX() << endl;
	::operator delete(p);
	return 0;
}
[/quote] ::new和::delete不太了解,如果可以这样的话那的确是封不住用户了,走的全都是全局重载。
雨中鹰 2014-05-18
  • 打赏
  • 举报
回复
引用 14 楼 qq120848369 的回复:
[quote=引用 13 楼 menglinaoxiang 的回复:]
[quote=引用 11 楼 qq120848369 的回复:]
栈上对象离开作用域会自己析构释放内存,你不需要为它显式的调用析构函数,delete同理。

楼主想做的可能与placement new有关,可以自己百度看一下。

#include <iostream>
using namespace std;

class Test{
public:
Test():x(3){cout << "ctor Test() is called!" << endl; }
~Test(){ cout << "dtor ~Test() is called!" << endl; }//(1)
int getX(){ return x; }
private:
int x;
void * operator new(size_t);
void operator delete(void*);//(2)
};

int main(){
Test *ptr = ::new Test(); //输出 3
cout << ptr->getX() << endl;
ptr->~Test(); //(4)
::delete ptr; //(5)

return 0;
}


可是我这样,用全局的new从堆上分配的内存,这样的情况也编译不通过,我做这个小例子本来是想不允许用户在堆上申请内存的,我上面的代码用了全局的::new与全局的::delete结果还是编译不通过,全局的new,delete与类内部的new,delete与析构函数之间有什么联系吗?
如果不重写析构函数上面的代码是可以通过的, 如果不在类中重写operator delete也是可以编译通过的,我不明白其中的关系[/quote]


楼主几个关键概念需要理解:
1,new是一个关键字,它的动作是:void* operator new(size_t) + operator new(size_t,void*ptr),既先分配一块内存,然后在内存上构造对象。
2,所以楼主代码里的::new和::delete是压根不存在的用法。 想要限制一个类在堆上创建是做不到的,虽然你可以private掉static void* operator new(size_t);和static void operator delete(void*);,这样用户调用new和delete会失败,但是用户完全可以显式指定使用::operartor new(size_t)+::operator new(size_t,void*ptr)搞定。[/quote]

版主好,::new ::delete确实是存在的,在c++ primer 中有讲到,我清楚全局的operator new是库函数,而类中重写的是操作符, 如果使用new操作符会先调用库函数operator new然后再调用类的构造函数, delete是先调用析构函数,再调用库函数operator delete。
你看看下面的代码及运行结果
#include <iostream>
using namespace std;

class Test{
public:
Test():x(3){cout << "ctor Test() is called!" << endl; }
int getX(){ return x; }
private:
int x;
void * operator new(size_t);
void operator delete(void*);//(2)
};

int main(){
Test *ptr = ::new Test(); //输出 3
cout << ptr->getX() << endl;
ptr->~Test(); //(4)
::delete ptr; //(5)

cout << "----------------" << endl;
Test *p = static_cast<Test*>(::operator new((size_t)sizeof(Test)));
cout << p->getX() << endl;
::operator delete(p);
return 0;
}

qq120848369 2014-05-18
  • 打赏
  • 举报
回复
#include <iostream>
#include <new>

class Test
{
public:
    Test()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
    ~Test()
    {
        std::cout << __FUNCTION__ << std::endl;
    }
    static void* operator new(size_t, void*); // private则彻底无法从堆上分配
private:
    static void* operator new(size_t);
    static void operator delete(void*);
};

static void* Test::operator new(size_t size, void* ptr)
{
    return ptr;
}

int main(int argc, char** argv) 
{
    Test t;

    // 你只能挡住这种用户
    // Test* p = new Test;
    // delete p;
    
    // 用户可以这样绕过限制
    void* ptr = ::operator new(sizeof(Test));
    Test* pobj = new (ptr) Test;
    pobj->~Test();
    ::operator delete(ptr);
    return 0;
}
qq120848369 2014-05-18
  • 打赏
  • 举报
回复
引用 13 楼 menglinaoxiang 的回复:
[quote=引用 11 楼 qq120848369 的回复:] 栈上对象离开作用域会自己析构释放内存,你不需要为它显式的调用析构函数,delete同理。 楼主想做的可能与placement new有关,可以自己百度看一下。
#include <iostream>
using namespace std;

class Test{
public:
	Test():x(3){cout << "ctor Test() is called!" << endl;	}
	~Test(){ cout << "dtor ~Test() is called!" << endl; }//(1)	
	int getX(){	return x; }
private:
	int x;
	void * operator new(size_t);
	void operator delete(void*);//(2)
};

int main(){
	Test *ptr = ::new Test(); //输出 3
	cout << ptr->getX() << endl;
	ptr->~Test(); //(4)
	::delete ptr; //(5)

	return 0;
}
可是我这样,用全局的new从堆上分配的内存,这样的情况也编译不通过,我做这个小例子本来是想不允许用户在堆上申请内存的,我上面的代码用了全局的::new与全局的::delete结果还是编译不通过,全局的new,delete与类内部的new,delete与析构函数之间有什么联系吗? 如果不重写析构函数上面的代码是可以通过的, 如果不在类中重写operator delete也是可以编译通过的,我不明白其中的关系[/quote] 楼主几个关键概念需要理解: 1,new是一个关键字,它的动作是:void* operator new(size_t) + operator new(size_t,void*ptr),既先分配一块内存,然后在内存上构造对象。 2,所以楼主代码里的::new和::delete是压根不存在的用法。 想要限制一个类在堆上创建是做不到的,虽然你可以private掉static void* operator new(size_t);和static void operator delete(void*);,这样用户调用new和delete会失败,但是用户完全可以显式指定使用::operartor new(size_t)+::operator new(size_t,void*ptr)搞定。
雨中鹰 2014-05-18
  • 打赏
  • 举报
回复
引用 11 楼 qq120848369 的回复:
栈上对象离开作用域会自己析构释放内存,你不需要为它显式的调用析构函数,delete同理。 楼主想做的可能与placement new有关,可以自己百度看一下。
#include <iostream>
using namespace std;

class Test{
public:
	Test():x(3){cout << "ctor Test() is called!" << endl;	}
	~Test(){ cout << "dtor ~Test() is called!" << endl; }//(1)	
	int getX(){	return x; }
private:
	int x;
	void * operator new(size_t);
	void operator delete(void*);//(2)
};

int main(){
	Test *ptr = ::new Test(); //输出 3
	cout << ptr->getX() << endl;
	ptr->~Test(); //(4)
	::delete ptr; //(5)

	return 0;
}
可是我这样,用全局的new从堆上分配的内存,这样的情况也编译不通过,我做这个小例子本来是想不允许用户在堆上申请内存的,我上面的代码用了全局的::new与全局的::delete结果还是编译不通过,全局的new,delete与类内部的new,delete与析构函数之间有什么联系吗? 如果不重写析构函数上面的代码是可以通过的, 如果不在类中重写operator delete也是可以编译通过的,我不明白其中的关系
雨中鹰 2014-05-18
  • 打赏
  • 举报
回复
引用 7 楼 lm_whales 的回复:
你的问题是啥?
#include <iostream>
using namespace std;

class Test{
public:
	Test():x(3){cout << "ctor Test() is called!" << endl;	}
	~Test(){ cout << "dtor ~Test() is called!" << endl; }//(1)	
	int getX(){	return x; }
private:
	int x;
	void * operator new(size_t);
	void operator delete(void*);//(2)
};

int main(){
	Test t;
	cout << t.getX() << endl;
	t.~Test(); //()3
	
	
	Test *ptr = ::new Test(); //输出 3
	cout << ptr->getX() << endl;
	ptr->~Test(); //(4)
	::delete ptr; //(5)

	return 0;
}
上述代码中,标有1,2,3,4,5,如果先将4,5两行代码注释掉,编译是不通过的,原因是3,2,1有冲突,我不明白为什么这里会有冲突,如果将2注释掉就可以。 4,5也是这样的问题,如果要想编译通过,要注释掉2, 如果不重新写自己的析构函数,那不注释掉2,有5也可以正常编译 你可以拷贝一下代码编译试一下,我在vs2012下编译的
qq120848369 2014-05-18
  • 打赏
  • 举报
回复
栈上对象离开作用域会自己析构释放内存,你不需要为它显式的调用析构函数,delete同理。 楼主想做的可能与placement new有关,可以自己百度看一下。
bobo_包子 2014-05-17
  • 打赏
  • 举报
回复
不知道你问啥
析构函数与operator delete你关系你搞清楚没? 而且你的 new和delete有问题的。请看我下面的代码
// c or c++.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <typeinfo>
#include <windows.h>
#include <exception>

using namespace std;

class A
{
public:
A(int _i) :i(_i)
{
cout << "ctor A: " << i << endl;
}
~A()
{
cout << "dctor: " << i << endl;
}
int get(){return i;}
protected:
private:
int i;
};

void *operator new(size_t n)
{
cout << "assigned " << n << "bytes" << endl;
return malloc(n);
}

void operator delete(void *p)
{
cout << "free memory" << endl;
free(p);
}

void my_fun()
{
A a1(1);
A *pa2 = new A(2);
delete pa2;
}

int _tmain(int argc, _TCHAR* argv[])
{
my_fun();
system("pause");
return 0;
}




1. 栈上的空间是不需要调用new和delete的,因为这是编译器分配的。
2. 我们new出啊来的对象,delete的时候首先是调用析构函数,然后再调用delete释放内存。

仅此而已。
lm_whales 2014-05-17
  • 打赏
  • 举报
回复
你的问题是啥?
unituniverse2 2014-05-17
  • 打赏
  • 举报
回复
没说不能同时存在吧

#include <conio.h>
#include <stdio.h>
#include <iostream>


class C
{
public:
	/*virtual*/ ~C() {};
	void operator delete (void *) {} /*= delete*/;
};

int main(void)
{
	C o1;

	_getch();
	return(0);
}

只要不是抽象类,同时存在没什么不可以。如果是抽象类的话delete重载必须可以访问。
menzi11 2014-05-17
  • 打赏
  • 举报
回复
根本不知道你想问什么,什么叫 "如果析构函数存在编译错误,析构函数与delete不可同时存在为什么"
雨中鹰 2014-05-16
  • 打赏
  • 举报
回复
引用 5 楼 u012565501 的回复:
好吧,我看错了,不过,析构函数一般都是在程序运行结束的时候调用的,不会在中间调用吧 [quote=引用 3 楼 u012565501 的回复:]

int main(){
Test t;
cout << t.getX() << endl;
cout << "----------------" << endl;
//t.~Test(); //如果析构函数存在编译错误 析构函数与delete不可同时存在为什么
Test *ptr = ::new Test(); //输出 3
cout << ptr->getX() << endl;
//ptr->~Test(); //如果析构函数存在编译错误
//::delete ptr; //如果析构函数存在编译错误
cout << "----------------" << endl;
Test *p = static_cast<Test*>(::operator new((size_t)sizeof(Test)));
cout << p->getX() << endl;
cout << "----------------" << endl;
::operator delete(p);
你的析构函数调用后,下面还用到这个被析构的类变量不是吗?
[/quote] 因为析构函数里没有对内存的操作,只是简单的输出,因此调用多遍是没有问题的
kivien 2014-05-16
  • 打赏
  • 举报
回复
好吧,我看错了,不过,析构函数一般都是在程序运行结束的时候调用的,不会在中间调用吧
引用 3 楼 u012565501 的回复:

int main(){
Test t;
cout << t.getX() << endl;
cout << "----------------" << endl;
//t.~Test(); //如果析构函数存在编译错误 析构函数与delete不可同时存在为什么
Test *ptr = ::new Test(); //输出 3
cout << ptr->getX() << endl;
//ptr->~Test(); //如果析构函数存在编译错误
//::delete ptr; //如果析构函数存在编译错误
cout << "----------------" << endl;
Test *p = static_cast<Test*>(::operator new((size_t)sizeof(Test)));
cout << p->getX() << endl;
cout << "----------------" << endl;
::operator delete(p);
你的析构函数调用后,下面还用到这个被析构的类变量不是吗?
zcdabing 2014-05-16
  • 打赏
  • 举报
回复
void * operator new(size_t); 这个是什么意思?重载new操作符?
kivien 2014-05-16
  • 打赏
  • 举报
回复

int main(){
Test t;
cout << t.getX() << endl;
cout << "----------------" << endl;
//t.~Test(); //如果析构函数存在编译错误 析构函数与delete不可同时存在为什么
Test *ptr = ::new Test(); //输出 3
cout << ptr->getX() << endl;
//ptr->~Test(); //如果析构函数存在编译错误
//::delete ptr; //如果析构函数存在编译错误
cout << "----------------" << endl;
Test *p = static_cast<Test*>(::operator new((size_t)sizeof(Test)));
cout << p->getX() << endl;
cout << "----------------" << endl;
::operator delete(p);
你的析构函数调用后,下面还用到这个被析构的类变量不是吗?
zcdabing 2014-05-16
  • 打赏
  • 举报
回复
引用 1 楼 zcdabing 的回复:
你在构造函数里调用析构函数? 我去
啊 不好意思看错了
zcdabing 2014-05-16
  • 打赏
  • 举报
回复
你在构造函数里调用析构函数? 我去

65,208

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧