我应该如何编写ISO C ++标准一致的自定义新的和删除操作符? [英] How should I write ISO C++ Standard conformant custom new and delete operators?

查看:136
本文介绍了我应该如何编写ISO C ++标准一致的自定义新的和删除操作符?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何编写ISO C ++标准一致的自定义 delete 运算符?



这是重载新增和删除的延续照亮C ++常见问题解答,操作符重载及其后续操作












b

第1节:编写符合标准的运算符





第2节:编写符合标准的 delete 运算符






(注意:这是一个 Stack Overflow的C ++常见问题。如果您想批评在此表单中提供常见问题解答的想法,请在meta上发布所有这一切将是做到这一点的地方。在 C ++聊天室中监控对该问题的答案,其中首先开始了常见问题解答,因此您的答案很可能会由想出想法的人阅读。)

注意:答案是基于Scott Meyers的更有效的C ++和ISO C ++标准。



解决方案

< h1>第I部分

此C ++常见问题解答条目解释了为什么可能需要重载 new delete 运算符为自己的类。



实现自定义新 / code>运算符



C ++标准(§18.4.1.1)定义 operator new as: / p>

  void * operator new(std :: size_t size)throw(std :: bad_alloc); 

C ++标准规定了这些操作符的定制版本在§3.7.3中必须遵守的语义, §18.4.1



让我们总结需求。



需求#1:它应该动态分配至少 size 字节的内存,并返回一个指向分配的内存的指针。从C ++标准,3.7.4.1.3节引用:


分配函数尝试分配所请求的存储量。如果它成功,它将返回一个存储块的开始的地址,其字节长度应至少与请求的大小一样大...


标准进一步强加:


...返回的指针应适当对齐,转换为任何完整对象类型的指针,然后用于访问分配的存储中的对象或数组(直到存储通过调用相应的解除分配函数显式地释放)。即使请求的空间大小为零,请求也可能失败。如果请求成功,则返回的值应该是不同于任何先前返回的值p1的非空指针值(4.10)p0,除非该值p1随后被传递给运算符 delete


这为我们提供了更多重要的要求:



需求#2:我们使用的内存分配函数(通常 malloc()或其他自定义分配器)应返回 / em>指向已分配内存的指针,可以转换为完整对象类型的指针并用于访问对象。



需求# 我们的自定义运算符 new 必须返回一个合法的指针,即使请求零字节。



new 原型可以推断出的明显要求是:



需求#4: strong>如果 new 不能分配所请求大小的动态内存,那么它应该抛出类型 std :: bad_alloc 。



但是!还有更多的东西,而不是眼睛:如果你仔细看看 new 运算符文档(来自标准的引用进一步详细说明) ,它说明:


如果 set_new_handler 已用于定义 new_handler 函数,则 new_handler 函数通过标准默认定义 operator new


要了解我们的自定义 new 需要支持此要求,我们应该了解:



new_handler set_new_handler



new_handler 是指向函数的指针的typedef,不返回任何值,
set_new_handler 是一个接受并返回 new_handler 的函数。



set_new_handler 的参数是指向函数运算符的指针new如果不能分配请求记忆。它的返回值是一个指向以前注册的处理程序函数的指针,如果没有上一个处理程序,则返回null。



代码示例清楚的一个时机: / p>

  #include< iostream> 
#include< cstdlib>

//如果操作符new不能分配足够的内存或错误,调用的函数
void outOfMemHandler()
{
std :: cerr< 无法满足对memory\\\
的请求;

std :: abort();
}

int main()
{
//设置new_handler
std :: set_new_handler(outOfMemHandler);

//请求大的内存大小,这将导致:: operator new失败
int * pBigDataArray = new int [100000000L];

return 0;
}



在上面的示例中, operator new (很可能)将无法为100,000,000个整数分配空间,并且函数 outOfMemHandler()将被调用,程序将在发出错误讯息



这里需要注意的是,当 operator new 无法满足内存请求,它会重复调用 new-handler 函数,直到 >找到足够的内存或没有更多的新处理程序。在上面的例子中,除非我们调用 std :: abort() outOfMemHandler() http://www.ideone.com/nF4iy\">反复呼叫。因此,处理程序应该确保下一次分配成功,或者注册另一个处理程序,或者注册没有处理程序,或者不返回(即终止程序)。如果没有新的处理程序,并且分配失败,运算符将抛出异常。



继续1
$ b



How should I write ISO C++ standard conformant custom new and delete operators?

This is in continuation of Overloading new and delete in the immensely illuminating C++ FAQ, Operator overloading, and its follow-up, Why should one replace default new and delete operators?

Section 1: Writing a standard-conformant new operator

Section 2: Writing a standard-conformant delete operator

(Note: This is meant to be an entry to Stack Overflow's C++ FAQ. If you want to critique the idea of providing an FAQ in this form, then the posting on meta that started all this would be the place to do that. Answers to that question are monitored in the C++ chatroom, where the FAQ idea started out in the first place, so your answer is very likely to get read by those who came up with the idea.)
Note: The answer is based on learnings from Scott Meyers' More Effective C++ and the ISO C++ Standard.

解决方案

Part I

This C++ FAQ entry explained why one might want to overload new and delete operators for one's own class. This present FAQ tries to explain how one does so in a standard-conforming way.

Implementing a custom new operator

The C++ standard (§18.4.1.1) defines operator new as:

void* operator new (std::size_t size) throw (std::bad_alloc);

The C++ standard specifies the semantics that custom versions of these operators have to obey in §3.7.3 and §18.4.1

Let us summarize the requirements.

Requirement #1: It should dynamically allocate at least size bytes of memory and return a pointer to the allocated memory. Quote from the C++ standard, section 3.7.4.1.3:

The allocation function attempts to allocate the requested amount of storage. If it is successful, it shall return the address of the start of a block of storage whose length in bytes shall be at least as large as the requested size...

The standard further imposes:

...The pointer returned shall be suitably aligned so that it can be converted to a pointer of any complete object type and then used to access the object or array in the storage allocated (until the storage is explicitly deallocated by a call to a corresponding deallocation function). Even if the size of the space requested is zero, the request can fail. If the request succeeds, the value returned shall be a non-null pointer value (4.10) p0 different from any previously returned value p1, unless that value p1 was sub-sequently passed to an operator delete.

This gives us further important requirements:

Requirement #2: The memory allocation function we use (usually malloc() or some other custom allocator) should return a suitably aligned pointer to the allocated memory, which can be converted to a pointer of an complete object type and used to access the object.

Requirement #3: Our custom operator new must return a legitimate pointer even when zero bytes are requested.

One of the evident requirements that can even be inferred from new prototype is:

Requirement #4: If new cannot allocate dynamic memory of the requested size, then it should throw an exception of type std::bad_alloc.

But! There is more to that than what meets the eye: If you take a closer look at the new operator documentation (citation from standard follows further down), it states:

If set_new_handler has been used to define a new_handler function, this new_handler function is called by the standard default definition of operator new if it cannot allocate the requested storage by its own.

To understand how our custom new needs to support this requirement, we should understand:

What is the new_handler and set_new_handler?

new_handler is a typedef for a pointer to a function that takes and returns nothing, and set_new_handler is a function that takes and returns a new_handler.

set_new_handler's parameter is a pointer to the function operator new should call if it can't allocate the requested memory. Its return value is a pointer to the previously registered handler function, or null if there was no previous handler.

An opportune moment for an code sample to make things clear:

#include <iostream>
#include <cstdlib>

// function to call if operator new can't allocate enough memory or error arises
void outOfMemHandler()
{
    std::cerr << "Unable to satisfy request for memory\n";

    std::abort();
}

int main()
{
    //set the new_handler
    std::set_new_handler(outOfMemHandler);

    //Request huge memory size, that will cause ::operator new to fail
    int *pBigDataArray = new int[100000000L];

    return 0;
}

In the above example, operator new (most likely) will be unable to allocate space for 100,000,000 integers, and the function outOfMemHandler() will be called, and the program will abort after issuing an error message.

It is important to note here that when operator new is unable to fulfill a memory request, it calls the new-handler function repeatedly until it can find enough memory or there is no more new handlers. In the above example, unless we call std::abort(), outOfMemHandler() would be called repeatedly. Therefore, the handler should either ensure that the next allocation succeeds, or register another handler, or register no handler, or not return (i.e. terminate the program). If there is no new handler and the allocation fails, the operator will throw an exception.

Continuation 1


这篇关于我应该如何编写ISO C ++标准一致的自定义新的和删除操作符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆