C++ 内存中类位置的成员是否取决于类定义中类成员的位置?

C++ 内存中类位置的成员是否取决于类定义中类成员的位置?,c++,class,memory,C++,Class,Memory,我有一个链类的一部分 template <typename T> class Part { public: part* prev; part* next; T data; } 模板 班级部分 { 公众: 第*部分上; 第*部分下一步; T数据; } T的大小现在还没有定义,我认为最好把它放在内存的末尾 例如,如果我向右移动8个字节,那么我肯定会转到下一个类成员的开头(在64位系统上),如果我首先放置了T,那么我不知道我会去哪里。我会影响类成员在内存中的位置,还是编译器会按照自

我有一个链类的一部分

template <typename T> 
class Part
{
public:

part* prev;
part* next;
T data;
}
模板
班级部分
{
公众:
第*部分上;
第*部分下一步;
T数据;
}
T的大小现在还没有定义,我认为最好把它放在内存的末尾

例如,如果我向右移动8个字节,那么我肯定会转到下一个类成员的开头(在64位系统上),如果我首先放置了T,那么我不知道我会去哪里。我会影响类成员在内存中的位置,还是编译器会按照自己的意愿做任何事情


我可以帮助您使用它吗?

我不能肯定,因为它是在不同的编译器之间定义的实现

我将此添加到您的代码中:

template <typename T>
class Part {
public:
    Part* prev;
    Part* next;
    T data;
};

template<typename T>
Part<T> makeClass(T value) {
   Part<T> part{};
   part.data = value;
   return part;
}

int main() {
    auto p = makeClass(12);
    return 0;
}
GCC

main:
        xor     eax, eax
        ret
part$ = 0
$T1 = 64
value$ = 72
Part<int> makeClass<int>(int) PROC       ; makeClass<int>, COMDAT
$LN3:
        mov     DWORD PTR [rsp+16], edx
        mov     QWORD PTR [rsp+8], rcx
        push    rsi
        push    rdi
        sub     rsp, 40                             ; 00000028H
        lea     rax, QWORD PTR part$[rsp]
        mov     rdi, rax
        xor     eax, eax
        mov     ecx, 24
        rep stosb
        mov     eax, DWORD PTR value$[rsp]
        mov     DWORD PTR part$[rsp+16], eax
        lea     rax, QWORD PTR part$[rsp]
        mov     rdi, QWORD PTR $T1[rsp]
        mov     rsi, rax
        mov     ecx, 24
        rep movsb
        mov     rax, QWORD PTR $T1[rsp]
        add     rsp, 40                             ; 00000028H
        pop     rdi
        pop     rsi
        ret     0
Part<int> makeClass<int>(int) ENDP       ; makeClass<int>

$T1 = 32
$T2 = 56
p$ = 80
main    PROC
$LN3:
        push    rsi
        push    rdi
        sub     rsp, 120                      ; 00000078H
        mov     edx, 12
        lea     rcx, QWORD PTR $T2[rsp]
        call    Part<int> makeClass<int>(int)      ; makeClass<int>
        lea     rcx, QWORD PTR $T1[rsp]
        mov     rdi, rcx
        mov     rsi, rax
        mov     ecx, 24
        rep movsb
        lea     rax, QWORD PTR p$[rsp]
        lea     rcx, QWORD PTR $T1[rsp]
        mov     rdi, rax
        mov     rsi, rcx
        mov     ecx, 24
        rep movsb
        xor     eax, eax
        add     rsp, 120                      ; 00000078H
        pop     rdi
        pop     rsi
        ret     0
main    ENDP
MSVC

main:
        xor     eax, eax
        ret
part$ = 0
$T1 = 64
value$ = 72
Part<int> makeClass<int>(int) PROC       ; makeClass<int>, COMDAT
$LN3:
        mov     DWORD PTR [rsp+16], edx
        mov     QWORD PTR [rsp+8], rcx
        push    rsi
        push    rdi
        sub     rsp, 40                             ; 00000028H
        lea     rax, QWORD PTR part$[rsp]
        mov     rdi, rax
        xor     eax, eax
        mov     ecx, 24
        rep stosb
        mov     eax, DWORD PTR value$[rsp]
        mov     DWORD PTR part$[rsp+16], eax
        lea     rax, QWORD PTR part$[rsp]
        mov     rdi, QWORD PTR $T1[rsp]
        mov     rsi, rax
        mov     ecx, 24
        rep movsb
        mov     rax, QWORD PTR $T1[rsp]
        add     rsp, 40                             ; 00000028H
        pop     rdi
        pop     rsi
        ret     0
Part<int> makeClass<int>(int) ENDP       ; makeClass<int>

$T1 = 32
$T2 = 56
p$ = 80
main    PROC
$LN3:
        push    rsi
        push    rdi
        sub     rsp, 120                      ; 00000078H
        mov     edx, 12
        lea     rcx, QWORD PTR $T2[rsp]
        call    Part<int> makeClass<int>(int)      ; makeClass<int>
        lea     rcx, QWORD PTR $T1[rsp]
        mov     rdi, rcx
        mov     rsi, rax
        mov     ecx, 24
        rep movsb
        lea     rax, QWORD PTR p$[rsp]
        lea     rcx, QWORD PTR $T1[rsp]
        mov     rdi, rax
        mov     rsi, rcx
        mov     ecx, 24
        rep movsb
        xor     eax, eax
        add     rsp, 120                      ; 00000078H
        pop     rdi
        pop     rsi
        ret     0
main    ENDP
part$=0
$T1=64
价值$=72
零件制造类(int)程序;makeClass,COMDAT
LN3美元:
mov DWORD PTR[rsp+16],edx
mov QWORD PTR[rsp+8],rcx
推挤性rsi
推动rdi
副rsp,40;00000028小时
lea rax,QWORD PTR部分$[rsp]
莫夫尔迪,拉克斯
异或eax,eax
mov ecx,24
代表stosb
mov eax,DWORD PTR价值$[rsp]
mov DWORD PTR部件$[rsp+16],eax
lea rax,QWORD PTR部分$[rsp]
移动rdi,QWORD PTR$T1[rsp]
移动rsi,rax
mov ecx,24
代表movsb
mov rax,QWORD PTR$T1[rsp]
加上可吸入悬浮粒子40;00000028小时
流行rdi
流行性rsi
ret 0
零件制造类(int)ENDP;制造类
$T1=32
$T2=56
p$=80
主进程
LN3美元:
推挤性rsi
推动rdi
副rsp,120;00000078H
mov edx,12
lea rcx,QWORD PTR$T2[rsp]
调用部件makeClass(int);制造类
lea rcx,QWORD PTR$T1[rsp]
mov rdi,rcx
移动rsi,rax
mov ecx,24
代表movsb
lea rax,QWORD PTR p$[rsp]
lea rcx,QWORD PTR$T1[rsp]
莫夫尔迪,拉克斯
移动rsi,rcx
mov ecx,24
代表movsb
异或eax,eax
加上rsp,120;00000078H
流行rdi
流行性rsi
ret 0
主端

查看从各种编译器生成的程序集可能有助于确定代码中发生的情况及其数据对齐方式。在第3级使用优化器查看这些值之后,将其更改为第2级、第1级、第1级,然后查看生成的程序集中的差异。这可能会给你一些见解


来自专业人士的提示-相信你的编译器

类的成员在内存中的顺序与类定义中的顺序相同。请注意,您不会只有一个
Part
类。您将有几个
Part
类,根据
T
的大小,每个类都有自己的布局。还不清楚你的意思是“向右移动8字节”,此外还有数据成员填充要考虑。根据
T
的大小和指针的大小,编译器可能会添加填充字节以正确对齐内存中的所有内容。如果一个类有虚拟成员,那么在该类中也会得到一个虚拟表指针,其位置是特定于实现的。在某些情况下,只需在类对象的内存中添加8字节,就可以执行伪虚拟函数,这样做有利可图吗??或者编译器不使用我在代码中没有用到的所有东西?编译器会在适当的时候添加填充。我宁愿信任编译器而不是我自己如果您想查看数据成员在特定实现中的顺序,请对每个成员使用
offsetof(MyClass,dataMember)
,并查看从类实例位于内存中的第一个字节开始的字节偏移量。这将帮助您了解编译器如何使用编译代码的选项排列数据成员。在gcc和clang的输出中,所有代码都经过了优化,因此查看结构在memory@idclev这就是为什么我向OP提到要更改优化器的级别。。。然后他们就能看到发生了什么。