Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 重载nothrow版本的new和delete_C++ - Fatal编程技术网

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);