这编译得很好:
#include <cstddef>
#include <stdlib.h>
typedef unsigned int uint;
class C{ // just here to be faithful to the original code
int y;
};
class A{
public:
typedef A this_type;
void* operator new(size_t enfacia_size, uint count){
size_t total_size
= enfacia_size
+ sizeof(int) * count; // the 'tail'
;
this_type *new_pt = (this_type *)malloc(total_size);
new_pt->count = count;
return new_pt;
};
uint count;
};
class B : public C, public A{
public:
int i;
};
int main(){
B *b_pt = new(5) B;
uint j=0;
j++;
};
这是gdb中显示的“问题”:
(gdb) b main
Breakpoint 1 at 0x80484e1: file try_offsets.ex.cc, line 32.
(gdb) r
Starting program try_offsets
Breakpoint 1, main () at try_offsets.cc:32
(gdb) n
(gdb) p &(b_pt->count)
$1 = (uint *) 0x804a00c
(gdb) x/10 b_pt
0x804a008: 5 0 0 0
0x804a018: 0 0 0 0
0x804a028: 0 135129
(gdb) p b_pt
$2 = (B *) 0x804a008
(gdb)
请注意,count 位于 0x804a00c,但分配给 count 时写入 0x804a008。现在有了 Rob 指出的变体,其中通过模板将这种类型设置为子项:
#include <cstddef>
#include <stdlib.h>
typedef unsigned int uint;
class C{ // just here to be faithful to the original code
int y;
};
template<typename this_type>
class A{
public:
void* operator new(size_t enfacia_size, uint count){
size_t total_size
= enfacia_size
+ sizeof(int) * count; // the 'tail'
;
this_type *new_pt = (this_type *)malloc(total_size);
new_pt->count = count;
return new_pt;
};
uint count;
};
class B : public C, public A<B>{
public:
int i;
};
int main(){
B *b_pt = new(5) B;
uint j=0;
j++;
};
我们得到正确的行为:
(gdb) b main
Breakpoint 1 at 0x80484e1: file try_offsets.ex.cc, line 32.
(gdb) r
Starting program
Breakpoint 1, main () at try_offsets.cc:32
(gdb) n
(gdb) p &(b_pt->count)
$1 = (uint *) 0x804a00c
(gdb) x/10 b_pt
0x804a008: 0 5 0 0
0x804a018: 0 0 0 0
0x804a028: 0 135129
(gdb)
不过有趣的是,当 this_type 设置为“A”时,使用此解决方案将无法编译:
class B : public C, public A<A>{
public:
int i;
};
给出:
try_offsets.cc:26:31: error: type/value mismatch at argument 1 in template parameter list for ‘template<class this_type> class A’
try_offsets.cc:26:31: error: expected a type, got ‘A’
我确定的解决方案:
#include <cstddef>
#include <stdlib.h>
typedef unsigned int uint;
class C{ // just here to be faithful to the original code
int y;
};
class A{
public:
typedef A this_type;
A(uint count):count(count){;}
void* operator new(size_t enfacia_size, uint count){
size_t total_size
= enfacia_size
+ sizeof(int) * count; // the 'tail'
;
this_type *new_pt = (this_type *)malloc(total_size);
return new_pt;
};
uint count;
};
class B : public C, public A{
public:
B(uint count):A(count){;}
int i;
};
int main(){
B *b_pt = new(5) B(5);
uint j=0;
j++;
};
虽然这打破了旧的惯例。分配器在分配点上方写入分配的长度是正常的。也就是说,例如,delete/free 如何知道堆上的块有多长。此外,由于 operator delete 不能带参数,这就是我们获取信息的方式。