destructor - Parameter "size" of member operator new[] in C++ -
4 classes in following codes: a, b, c , d.
they have member operator new[]
.
besides,
- b has constructor;
- c has destructor;
- d has member
operator delete[]
.
the parameter size
of member operator new[]
, sizeof
of 4 classes output:
new[] 40 new[] b 40 new[] c 48 new[] d 48 sizeof(a) 4 sizeof(b) 4 sizeof(c) 4 sizeof(d) 4
what's reason differences of size
?
codes(ugly know):
#include <iostream> using namespace std; class { int i; public: static void* operator new[](std::size_t size) throw(std::bad_alloc) { cout << "new[] " << size << endl; return malloc(size); } }; class b { int i; public: static void* operator new[](std::size_t size) throw(std::bad_alloc) { cout << "new[] b " << size << endl; return malloc(size); } b() {} }; class c { int i; public: static void* operator new[](std::size_t size) throw(std::bad_alloc) { cout << "new[] c " << size << endl; return malloc(size); } ~c() {} }; class d { int i; public: static void* operator new[](std::size_t size) throw(std::bad_alloc) { cout << "new[] d " << size << endl; return malloc(size); } static void operator delete[](void* p, std::size_t size) { free(p); } }; int main() { a* = new a[10]; b* b = new b[10]; c* c = new c[10]; d* d = new d[10]; cout << "sizeof(a) " << sizeof(a) << endl; cout << "sizeof(b) " << sizeof(b) << endl; cout << "sizeof(c) " << sizeof(c) << endl; cout << "sizeof(d) " << sizeof(d) << endl; }
about os , compiler:
compiling: same results clang++ , g++
clang++ test.cpp -o test -std=c++11 g++ test.cpp -o test -std=c++11
os: linux mint 18.2 cinnamon 64-bit
compilers:
clang++ -v
clang version 3.8.0-2ubuntu4 (tags/release_380/final) target: x86_64-pc-linux-gnu thread model: posix installeddir: /usr/bin found candidate gcc installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9 found candidate gcc installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9.3 found candidate gcc installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0 found candidate gcc installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/6.0.0 found candidate gcc installation: /usr/lib/gcc/x86_64-linux-gnu/4.9 found candidate gcc installation: /usr/lib/gcc/x86_64-linux-gnu/4.9.3 found candidate gcc installation: /usr/lib/gcc/x86_64-linux-gnu/5.4.0 found candidate gcc installation: /usr/lib/gcc/x86_64-linux-gnu/6.0.0 selected gcc installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0 candidate multilib: .;@m64 selected multilib: .;@m64 found cuda installation: /usr/local/cuda
g++ -v
using built-in specs. collect_gcc=g++ collect_lto_wrapper=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper target: x86_64-linux-gnu configured with: ../src/configure -v --with-pkgversion='ubuntu 5.4.0-6ubuntu1~16.04.4' --with-bugurl=file:///usr/share/doc/gcc-5/readme.bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu thread model: posix gcc version 5.4.0 20160609 (ubuntu 5.4.0-6ubuntu1~16.04.4)
these 8 bytes used store information regarding has been allocated in order destruct objects correctly (the program needs know how many objects need destroyed) , call t::operator delete[]
correct second parameter. according generated assembly (see end of answer), value stored number of elements (here 10
).
basically:
for
a
,b
, destructor no-op, there no need know how many elements must destroyed, , don't have user-defineddelete[]
, compiler use default one, apparently not care second parameter;for
c
, destructor used-defined, must called (i don't know why not optimized... ), program needs know how many objects destroyed;for
d
, have user-definedd::operator delete[]
, program must remember allocated size in order sendd::operator delete[]
when necessary.
if replace int
attribute type has non-trivial destructor (e.g. std::vector<int>
), notice these 8 bytes both a
, b
.
you can @ generated assembly c
(g++ 7.2, no optimization):
; c *c = new c[10]; call c::operator new[](unsigned long) mov qword ptr [rax], 10 ; store "10" (allocated objects) add rax, 8 ; increase pointer 8 mov qword ptr [rbp-24], rax ; delete[] c; cmp qword ptr [rbp-24], 0 je .l5 mov rax, qword ptr [rbp-24] ; c sub rax, 8 mov rax, qword ptr [rax] ; retrieve number of objects lea rdx, [0+rax*4] ; retrieve associated size (* sizeof(c)) mov rax, qword ptr [rbp-24] lea rbx, [rdx+rax] .l7: cmp rbx, qword ptr [rbp-24] ; loops destruct allocated objects je .l6 sub rbx, 4 mov rdi, rbx call c::~c() jmp .l7 .l6: mov rax, qword ptr [rbp-24] sub rax, 8 mov rax, qword ptr [rax] ; retrieve number of allocated objects add rax, 2 ; add 2 = 8 bytes / sizeof(c) lea rdx, [0+rax*4] ; number of allocated bytes mov rax, qword ptr [rbp-24] sub rax, 8 mov rsi, rdx mov rdi, rax call operator delete[](void*, unsigned long)
if not familiar assembly, here arranged c++ version of happens under hood:
// c *c = new c[10]; char *c_ = (char*)malloc(10 * sizeof(c) + sizeof(std::size_t)); // inside c::operator new[] *reinterpret_cast<std::size_t*>(c_) = 10; // stores number of allocated objects c *c = (c*)(c_ + sizeof(std::size_t)); // retrieve "correct" pointer // delete[] c; -- destruction of allocated objects char *c_ = (char*)c; c_ -= sizeof(std::size_t); // retrieve original pointer std::size_t n = // retrieve number of allocated objects *reinterpret_cast<std::size_t*>(c_); n = n * sizeof(c); // = n * 4, retrieve allocated size c_ = (char*)c + n; // retrieve "end" pointer while (c_ != (char*)c) { c_ -= sizeof(c); // next object (*reinterpret_cast<c*>(c_)).~c(); // destruct object } // delete[] c; -- freeing of memory char *c_ = (char*)c; c_ -= sizeof(std::size_t); std::size_t n = *reinterpret_cast<std::size_t*>(c_); // retrieve number of allocated objects n = n * sizeof(c) + sizeof(std::size_t); // note: compiler funky computation instead of // this, found clearer ::operator delete[](c_, n);
now you're happy know compiler of ;)
Comments
Post a Comment