堆栈上的参考用途有多少内存

How much memory does a reference use on the stack

本文关键字:多少 内存 参考 堆栈      更新时间:2023-10-16

使用通过参考时,对象的内存将进入堆栈?
我认为使用通过引用的通行证不会使对象的副本副本,并且堆栈上不会有对象的大小。在下面的代码中,似乎对象的整个大小被推到堆栈上,无论是参考还是值。

#include <iostream>
#include <stdint.h>
struct structWithSize_s{
  char data[1024*2];
};
void usePassPointer(structWithSize_s *t,uint64_t addr){
    int i;
    std::cout << "usePassPointer: stack: " << std::hex << &i 
              << std::dec << " size on stack: " << addr-uint64_t(&i) << std::endl;
    i = int(t->data[0]);
}
void usePassByValue(structWithSize_s t,uint64_t addr){
    int i;
    std::cout << "usePassByValue: stack: " << std::hex << &i 
              << std::dec << " size on stack: " << addr-uint64_t(&i) << std::endl;
    i = int(t.data[0]);
    usePassPointer(&t,uint64_t(&i));
}
void usePassByRef(structWithSize_s &t,uint64_t addr){
    int i;
    std::cout << "usePassByRef: stack: " << std::hex << &i 
              << std::dec << " size on stack: " << addr-uint64_t(&i) << std::endl;
    i = int(t.data[0]);
    usePassByValue(t,uint64_t(&i));
}
int main(void){
    int i;
    std::cout << "Base Stack: " << std::hex << &i << std::dec << std::endl;
    structWithSize_s t;
    std::cout << "Sizeof(t): " << sizeof(t) <<  std::endl;
    usePassByRef(t,uint64_t(&i));
    char d;
    std::cin >> d;
    return 0;
}

输出:

$ g++ -std=c++0x -O0 -fno-implement-inlines -g t.cpp
$ ./a.out
Base Stack: 0x7ffff2826c8c
Sizeof(t): 2048
usePassByRef: stack: 0x7ffff282645c size on stack: 2096
usePassByValue: stack: 0x7ffff2825c1c size on stack: 2112
usePassPointer: stack: 0x7ffff2825bdc size on stack: 64

您的测试堆栈大小的方法是不可靠的。

为什么不直接伸向马的嘴:

让我们设置场景:

struct X {
  char data[1024];
};
void by_value(X x);
void by_ref(X& x);
void by_ptr(X* x);
void test_by_value()
{
    X x;
    by_value(x);
}
void test_by_ref()
{
    X x;
    by_ref(x);
}
void test_by_ptr()
{
    X x;
    by_ptr(&x);
}

现在让我们看看我们实际拥有的东西:

test_by_value():                     # @test_by_value()
        sub     rsp, 2056 // <-- stack increase
        lea     rsi, [rsp + 1032]
        mov     ecx, 128
        mov     rdi, rsp
        rep movsq
        call    by_value(X)
        add     rsp, 2056
        ret
test_by_ref():                       # @test_by_ref()
        sub     rsp, 1032  // <-- stack increase
        lea     rdi, [rsp + 8]
        call    by_ref(X&)
        add     rsp, 1032
        ret
test_by_ptr():                       # @test_by_ptr()
        sub     rsp, 1032  // <-- stack increase
        lea     rdi, [rsp + 8]
        call    by_ptr(X*)
        add     rsp, 1032
        ret

您可以在test_by_value中看到,堆栈在2056年增加到了大约与局部x变量(1024( 复制参数 其他堆栈Shenanigans的大小的大小。

虽然在test_by_reftest_by_ptr中,1032增加了堆栈,这证明对象x在堆栈上未重复。

您有:经验证明,通过参考文献不使用整个对象的堆栈。


回到您的测试方法。在高中和某种程度上,我通过以相同的方式来显示"堆栈概念":观察本地变量的地址并进行比较。

但是,我对此方法有厌恶。甚至没有谈论可移植性问题。但是,除非您非常了解ABI合同以及编译器的实施和优化实施(是的,即使使用-O0进行了一些优化(,您将获得结果,您将获得结果,您并不真正了解它们的来源,并且您急于给他们解释这些解释不正确。


您可以在此处看到它:https://godbolt.org/g/8562ld

带有

的叮当躯干
-std=c++1z -Wall -Wextra -O3 -fno-implement-inlines -march=native

GCC给出了类似的结果

我认为使用通过引用的通行证不会成为对象的副本

确实没有。

在堆栈上使用参考用途

如果不需要存储,则可能根本没有。

但是,除非该函数在内联扩展,否则参考参数必须在实践中具有存储。这是获取引用将在内存中占据的大小的技巧:

struct test {
    structWithSize_s &t;
};
size_t size = sizeof(test);

实际上,它可能与指针完全相同。

i在堆栈上的 structWithSize_s t之前。sizeof(structWithSize_s)是您正在测量的,而不是sizeof(structWithSize_s &)

structWithSize_s t下方移动i