引用在堆栈上使用了多少内存

时间:2017-04-20 15:46:29

标签: c++ linux

使用按引用传递时,对象的内存量是多少? 我认为使用pass by reference不会复制对象,也不会有堆栈对象的大小。 在下面的代码中,似乎对象的整个大小被推入堆栈,无论它是引用还是值。

"John Smith"

输出:

#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;
}

3 个答案:

答案 0 :(得分:4)

你的测试堆栈大小的方法是......不可靠,温和地说。

为什么不直接去马的嘴巴:

让我们设置场景:

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)的大小+复制参数+其他堆栈恶作剧的大小。< / p>

test_by_reftest_by_ptr中,堆栈增加1032,证明对象x不会在堆栈中重复。

你有:经验证明,通过引用传递不会将堆栈用于整个对象。

回到你的测试方法。在高中和某种程度上的教师,我被展示了#34;堆栈概念&#34;通过以同样的方式做事:观察局部变量的地址并比较它们。

但是我厌恶这种方法。甚至没有谈论可移植性问题。但是除非你非常了解ABI契约以及编译器实现和优化实现(是的,编译器甚至用-O0进行了一些优化),你得到的结果你并不真正理解它们来自哪里和你急于给他们不正确的解释。

你可以在这里看到它:https://godbolt.org/g/8562LD

clang trunk with

-std=c++1z -Wall -Wextra -O3 -fno-implement-inlines -march=native

gcc给出了类似的结果

答案 1 :(得分:2)

  

我认为使用pass by reference不会复制对象

确实,它没有。

  

引用在堆栈上使用了多少内存

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

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

struct test {
    structWithSize_s &t;
};

size_t size = sizeof(test);

在实践中,它可能与指针完全相同。

答案 2 :(得分:0)

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

i移到structWithSize_s t下方。