C++ 重载nothrow版本的new和delete
请参阅以下代码:C++ 重载nothrow版本的new和delete,c++,C++,请参阅以下代码: #include<iostream> #include<stdlib.h> #include<new> using namespace std; class ex { int x; public: ex():ex(0){} ex(int x):x(x) { //cout<<"\nConstructor"; } void *operator new(size_t
#include<iostream>
#include<stdlib.h>
#include<new>
using namespace std;
class ex
{
int x;
public:
ex():ex(0){}
ex(int x):x(x)
{
//cout<<"\nConstructor";
}
void *operator new(size_t siz)
{
void *p;
cout<<"\nOverloaded new operator normal version";
p=malloc(siz);
if(p==NULL)
{
bad_alloc ba;
throw ba;
}
else
return p;
}
void operator delete(void *p,size_t sz)
{
cout<<"\nOverloaded delete normal version:"<<sz;
free(p);
}
void *operator new(size_t siz,const nothrow_t &tag)
{
void *p;
cout<<"\nOverloaded new operator nothrow version";
p=malloc(siz);
if(p==NULL)
{
return 0;
}
else
return p;
}
void operator delete(void *p,const nothrow_t &tag)
{
cout<<"\nOverloaded delete nothrow version";
free(p);
}
void *operator new[](size_t siz)
{
void *p;
cout<<"\nOverloaded new operator normal version in array";
p=malloc(siz);
if(p==NULL)
{
bad_alloc ba;
throw ba;
}
else
return p;
}
void operator delete[](void *p,size_t sz)
{
cout<<"\nOverloaded delete normal version in array:"<<sz;
free(p);
}
void *operator new[](size_t siz,const nothrow_t &tag)
{
void *p;
cout<<"\nOverloaded new operator nothrow version in array";
p=malloc(siz);
if(p==NULL)
{
return 0;
}
else
return p;
}
void operator delete[](void *p,const nothrow_t &tag)
{
cout<<"\nOverloaded delete nothrow version in array";
free(p);
}
};
int main()
{
ex *pt;
pt=new ex;
delete pt;
pt=new ex[10];
delete[] pt;
pt=new(nothrow) ex;
delete pt;
pt=new(nothrow) ex[10];
delete[] pt;
}
我的问题是:
1为什么不调用删除的行版本
2我可以在nothrow版本的delete中使用大小参数。像
3删除的nothrow版本有何用途
4I在新版本和新版本[]中使用了相同的代码,删除和删除[]
但一个是正态变量,另一个是数组变量
这个
5编译器发出警告:“运算符new”不能返回NULL
除非声明为“throw”或-fcheck new有效,否则如何
过来吧
new的默认行为
除非显式调用newstd::nothrow,否则C++会在new失败时抛出bad_alloc异常
这不受用户是否重载运算符new的问题的影响
因此,当您调用new而不传递std::nothrow时,您将无法到达nothrow版本。即使你超载了。或者不是
纽诺思罗
请注意,您的nothrow版本确实会抛出错误,但这不是正确的做法。它应该看起来像:
void* operator new(size_t size, const nothrow_t& tag) noexcept
{
void* p = malloc(size);
return p; // don't throw from the nothrow version of new
}
然而,这并不会改变所解释的行为:要达到nothrow版本的new,您必须显式地调用它,正如您在代码中看到的那样
禁用异常
有些编译器允许禁用异常,例如gcc中的标志-异常。这取决于编译器,但在大多数情况下,如果不是全部——抛开MSVC的旧版本不谈——禁用异常不会导致异常不会被抛出,而只会使编译器假定不会抛出异常,如果调用new失败,则仍会抛出异常
见:
gcc示例:
有关问题:
也可以很好地阅读:
运算符删除
delete运算符不应引发异常。它的两个版本,nothrow和正常非nothrow
那么,运算符delete的nothrow版本有什么用途呢
如果调用new来分配对象,则内存已成功分配,但该对象的构造函数引发了异常,则新操作将失败,从而传播构造函数引发的异常。但在此之前,需要释放获得的内存。这是通过调用delete操作符自动完成的。如果刚刚失败的new是nothrow版本,那么要调用的delete操作符将是nothrow,否则它将是正常的。请注意,两个版本的delete操作符都不会也不应该抛出。还请注意,您不能单独调用nothrow版本的delete运算符!但是您可以创建一个场景,在其中调用它
例如:
struct A {
A() {
throw "bahh";
}
};
void operator delete(void* ptr) noexcept {
std::cout << "normal delete" << std::endl;
free(ptr);
}
void operator delete(void* ptr, const std::nothrow_t&) noexcept {
std::cout << "nothrow delete" << std::endl;
free(ptr);
}
int main() {
std::cout << "calling new A" << std::endl;
try {
new A(); // prints: normal delete
}
catch(const char* s) {
std::cout << s << std::endl; // bahh
}
std::cout << "calling new(std::nothrow) A" << std::endl;
try {
new(std::nothrow) A(); // prints: nothrow delete
}
catch(const char* s) {
std::cout << s << std::endl; // bahh
}
}
代码:
见:
如果你还没有,你应该看看,正如前面提到的 请注意,“标准”大小的删除运算符是 仅适用于C++14及更高版本和 仅适用于“普通运营商”,即全球范围内的运营商。 为了完整起见,C++17在new和delete中添加了一组重载,用于对齐过度的内存。我还没有看过C++20销毁删除重载 使用特定于类的大小的delete重载没有多大意义,因为您可以使用sizeof ex轻松访问对象的大小。那么,对于数组版本可能会有一些用处 您始终可以显式调用您的重载,例如
ex::operator delete(pt, foo);
请把换行符放在这一行的末尾。首先,这使输出更具可读性。其次,它会刷新流中的缓冲区,以便输出立即可见。@UlrichEckhardt\n不一定刷新缓冲区。只有std::endl会这样做。没错,不一定。在本例中,它确实如此,因为默认情况下std::cout与C stdio流同步,并且默认情况下stdout是行缓冲的。不过,使用std::endl或者更显式的std::flush确实更好。很抱歉,我会在那一行出错,但我会将那一行ifp==NULL{bad_alloc ba;throw ba;}更改为ifp==NULL{return 0;}但不调用nothrow版本的delete运算符编译器发出警告:“运算符new”不得返回NULL,除非声明为“throw”或-fcheck new有效|无需检查p==NULL,您只需返回p即可;声明throw是C++98中noexceptok的等价物,但是我不知道还有其他四个问题,你能帮我解决吗谢谢你的帮助和回答
struct A {
A() {
throw "bahh";
}
};
void operator delete(void* ptr) noexcept {
std::cout << "normal delete" << std::endl;
free(ptr);
}
void operator delete(void* ptr, const std::nothrow_t&) noexcept {
std::cout << "nothrow delete" << std::endl;
free(ptr);
}
int main() {
std::cout << "calling new A" << std::endl;
try {
new A(); // prints: normal delete
}
catch(const char* s) {
std::cout << s << std::endl; // bahh
}
std::cout << "calling new(std::nothrow) A" << std::endl;
try {
new(std::nothrow) A(); // prints: nothrow delete
}
catch(const char* s) {
std::cout << s << std::endl; // bahh
}
}
ex::operator delete(pt, foo);