当前位置:网站首页>Operator new, operator delete supplementary handouts
Operator new, operator delete supplementary handouts
2022-07-26 03:53:00 【GarryLau】
1. understand new-handler
When operator new When a memory allocation requirement cannot be met , It throws an exception ( Of course you can nothrow edition ), When operator new Before throwing an exception to reflect an unmet memory requirement , It will first call an error handling function new-handler( Of course, it must be called first set_new_handler.
for example :
#include <new>
void outOfMem() {
std::cerr << "Unable to satifsy request for memory\n";
std::abort();
}
int main() {
std::set_new_handler(outOfMem);
int *pBigDataArray = new int[100000000L];
}
For more information, please refer to references 1 Of Clause 49: understand new-handler act (Understand the behavior of the new-handler)P240.
2. understand new and delete Reasonable replacement time of
Understand when it makes sense to replace new and delete.
Replace the standard library operator new、operator delete Common reasons :
2.1 Used to detect errors in use .
a. take new The resulting memory delete Failure to do so will result in memory leaks (memory leaks);
b. stay new The resulting memory is processed multiple times delete Can lead to uncertain behavior ;
c. Data due to various programming errors ”overruns“( The write point is after the allocated block ) or ”underruns“( The write point is before the start of the allocated block ).【 If you customize one operator new, You can over allocate memory , With extra space ( Before or after the customer's block ) Place specific byte patterns】.operator delete It is possible to check whether the above signature is intact , If no, it means that at some point in the allocation area overrunns or underruns,operator delete Sure log Facts and pointers to problems ( Personal understanding , Can be in operator delete When checking the specific byte patterns Has it changed ).
2.2 To enhance effectiveness
compiler ( Standard library ) Provided operator new and operator delete Take the golden mean , You need to be moderately friendly to every task , But not the best performance for any particular person . Self defined operator new and operator delete Performance is better than the default version , Custom version It's quite fast , Sometimes it's much faster , and Less memory required , Save up to 50%. For some programs, the standard library operator new and operator delete Replacing it with a customized version is one of the ways to achieve significant performance improvements .
2.3 To collect usage statistics
Using custom operator new and operator delete You should know how the developed software uses dynamic memory . such as , How about the size distribution of allocation blocks ? How about the life distribution ? They tend to take FIFO( fifo ) Sequence or LIFO( Last in, first out ) Order or random order to distribute and return ? Whether their application patterns change over time , That is, the software has different allocation in different execution stages / Return form ? What is the maximum dynamic allocation required at any time ? Use customization operator new and operator delete Easy to collect this information .
#pragma once
#include <new>
#include <cstdlib>
#include <stdexcept>
#include <iostream>
static const int kSignature = 0xDEADBEEF;
void* operator new(size_t size) {
if(void* mem = malloc(size + 2 * sizeof(int))) {
*((int*)mem) = kSignature;
*((int*)((unsigned char*)mem + sizeof(int) + sizeof(unsigned char)*size)) = kSignature;
std::cout << "malloc successfully" << std::endl;
return (unsigned char*)mem + sizeof(int);
}
else {
throw std::bad_alloc();
}
}
void operator delete(void *mem) noexcept {
std::cout << "Entering self-define operator delete...\n";
if(mem) {
/* Be careful , Under normal circumstances operator delete There is no way to verify overuns, Because you don't know the memory size, you can't add an offset Maybe you would say add an extra parameter , for example ,void operator delete(void *mem, int extra) noexcept But this form will only be called when there is an exception in the constructor */
// Of course, there are other methods to verify overuns, For example delete Perform active verification by offsetting according to the size of the requested memory
if((*(int*)((unsigned char*)mem - sizeof(int)) == kSignature)) {
free((unsigned char*)mem - sizeof(int));
std::cout << "free successfully" << std::endl;
}
else{
std::cerr << "memory underruns!!!" << std::endl;
}
}
}
auto test_operator_new_main() -> void {
std::cout << "testing operator new & operator delete for overruns&underruns..." << std::endl;
int *ptr = new int;
*((unsigned char*)ptr - 2) = 'P';
delete ptr;
std::cout << "------------------------------" << std::endl;
}
compiler cmake -G "Visual Studio 15 2017" -A x64 .. Result ( This running result meets the design expectation ):
testing operator new & operator delete for overruns&underruns...
malloc successfully
Entering self-define operator delete...
memory underruns!!!
------------------------------
compiler cmake -G "MinGW Makefiles" .. Result ( This operation result does not meet the design expectation ):
testing operator new & operator delete for overruns&underruns...
malloc successfully
The results show that the results are different under different compilers ,"MinGW Makefiles" Should call the standard library from time to time operator delete, The customized version is not used .
2.4 To detect usage errors
Such as 2.3 Section description .
2.5 To collect usage statistics of dynamically allocated memory
Such as 2.3 Section description .
2.6 In order to increase the speed of distribution and return
( Standard library ) Universal distributors tend to ( Although not always ) Slower than custom allocators , Especially when the custom allocator is specially designed for a specific type of object .
2.7 In order to reduce the extra space overhead caused by the default memory manager
General purpose memory managers tend to ( Although not always ) Not only is it slower than a custom allocator , And often uses more memory , Because they often have some extra overhead on each allocation block .
2.8 To compensate for the non optimal parity in the default allocator
stay x86 Architecturally double If it is 8-byte Alignment is the fastest access , But the compiler comes with operator new Dynamic allocation is not guaranteed double take 8 Byte alignment . here , Will default to operator new Replace with a 8 Byte version can greatly improve program efficiency .
2.9 In order to cluster related objects
If some data are often used together , And you hope to minimize the frequency of page missing exceptions when processing these data , So create a heap It makes sense , Use new and delete Of placement Version allows these data to be clustered on as few memory pages as possible .
2.10 In order to obtain unconventional behavior
Sometimes I hope operator new and operator delete Do what the compiler default version doesn't do . For example, custom operator delete Overwrite the returned content with 0.
3. To write new and delete We need to stick to the routine
3.1 Handle 0 bytes Memory application for
C++ Regulations , Even if the customer requires 0 bytes,operator new You also have to return a legal pointer , So heavy load operator new It should be able to handle 0 byte apply .
In response 0 bytes Before applying for memory, you need to introduce EBO,Empty Base Optimization Blank base class optimization . That is, if the base class is empty , Then the size of its subclass is the size of subclass members .
#include <iostream>
#include <typeinfo>
#include <stdio.h>
namespace test_ebo {
class Empty{
};
class Empty2{
};
class Derived1 : public Empty {
};
class Derived2 : public Empty {
private:
char c_;
};
class Derived3 : public Empty {
private:
int i_;
};
class MultipleDerived : public Derived1 {
};
class DerivedMultiBase : public Empty, public Empty2 {
};
auto main() -> int {
std::cout << "testing test_ebo......\n" << std::endl;
std::cout << "sizeof(Empty): " << sizeof(Empty) << std::endl; // 1
std::cout << "sizeof(Derived1): " << sizeof(Derived1) << std::endl; // 1
std::cout << "sizeof(Derived2): " << sizeof(Derived2) << std::endl; // 1
std::cout << "sizeof(Derived3): " << sizeof(Derived3) << std::endl; // 4
std::cout << "sizeof(MultipleDerived): " << sizeof(MultipleDerived) << std::endl; // 1
std::cout << "sizeof(DerivedMultiBase): " << sizeof(DerivedMultiBase) << std::endl; // 1
std::cout << typeid(MultipleDerived).name() << std::endl;
std::cout << typeid(DerivedMultiBase).name() << std::endl;
return 0;
}
}
cmake -G "MinGW Makefiles" .. compile , Output :
sizeof(Empty): 1
sizeof(Derived1): 1
sizeof(Derived2): 1
sizeof(Derived3): 4
sizeof(MultipleDerived): 1
sizeof(DerivedMultiBase): 1
N8test_ebo15MultipleDerivedE
N8test_ebo16DerivedMultiBaseE
Processing applications 0 bytes An example of :
void* operator new(std::size_t size) {
if(0 == size) {
size = 1; // take 0-byte As 1-byte apply
}
while(true) {
// Try to assign size bytes
if( Distribution succeeded ) {
return( Pointer to the allocated memory )
}
// Allocation failed : Find out the current new-handling function
new_handler globalHandler = set_new_handler(0);
set_new_handler(globalHandler);
if(globalHandler)(*globalHandler)();
else throw std::bad_alloc();
}
}
3.2 Be careful operator new Will be inherited by subclasses
class Base {
public:
static void* operator new(size_t size);
};
class Derived: public Base {
}; // hypothesis Derived Not a statement operator new
Derived* p = new Derived; // Called here Base::operator new
If Base exclusive operator new Not designed for Base Subclasses of ( In fact, this is often the case ), Then you should use the standard library when applying for subclass object memory operator new, Like this :
void* Base::operator new(size_t size) {
if(size != sizeof(Base)) {
// If the size is not the size of the base class, use the operator new
return ::operator new(size);
}
// ...... // Or deal with it here
}
3.3 more operator new For details, please move Reference And hands-on experiments
Reference
- Scott Meyers. Effective C++ Improve program and design 55 Specific practices ( The third edition ), Electronic industry press ,2011.
边栏推荐
- Find my technology | the Internet of things asset tracking market has reached US $6.6 billion, and find my helps the market develop
- File upload error: current request is not a multipart request
- Failed to install the hcmon driver
- 想要做好软件测试,可以先了解AST、SCA和渗透测试
- Visio: how do Gantt charts merge cells? Solution: overwrite cells
- 基于移位寄存器的同步FIFO
- 苹果在其产品中拿掉了最后一颗Intel芯片
- booking.com缤客上海面经
- [unity3d shader] character projection and reflection
- zk-SNARK:关于私钥、环签名、ZKKSP
猜你喜欢
随机推荐
Kbpc1510-asemi large chip 15A rectifier bridge kbpc1510
让百度收录,爬虫自己网站
Apply for SSL certificate, configure SSL certificate for domain name, and deploy server; Download and installation of SSL certificate
容器跑不动?网络可不背锅
Navicat connects to MySQL database on Cloud Server
【单片机仿真项目】外部中断0控制8个发光二极管闪烁
The B2B2C multi merchant system has rich functions and is very easy to open
tf.truncated_ Normal() usage
《opencv学习笔记》-- 重映射
How does redis implement persistence? Explain the AOF trigger mechanism and its advantages and disadvantages in detail, and take you to quickly master AOF
Find My技术|物联网资产跟踪市场规模达66亿美元,Find My助力市场发展
Brief tutorial for soft exam system architecture designer | case analysis and problem solving skills
Failed to install the hcmon driver
【单片机仿真项目】外部中断0和1控制两位数码管进行计数
Worked overtime for a week to develop a reporting system. This low code free it reporting artifact is very easy to use
ZK snark: about private key, ring signature, zkksp
安装VMware报错failed to install the hcmon driver
Aike AI frontier promotion (7.18)
基于Caffe ResNet-50网络实现图片分类(仅推理)的实验复现
Navicat连接云端服务器上的MySQL数据库






![[create interactive dice roller application]](/img/38/7bb0499bb70c4469428e841fa9c725.png)


