C ++中正确的堆栈和堆使用情况?

我已经编程了一段时间,但主要是Java和C#。 我从来没有必要自己管理记忆。 我最近开始使用C ++进行编程,我对于何时应该将东西存储在堆栈上以及何时将其存储在堆上有些困惑。

我的理解是,非常频繁访问的变量应该存储在堆栈中,并且对象,很少使用的变量以及大型数据结构都应该存储在堆中。 这是正确的还是我不正确?


不,堆栈和堆之间的区别不是性能。 它的使用寿命:函数内部的任何局部变量(任何你不需要malloc()或new)的东西都在栈上。 从功能返回时它会消失。 如果你想要的东西比声明它的函数寿命更长,你必须在堆上分配它。

class Thingy;

Thingy* foo( ) 
{
  int a; // this int lives on the stack
  Thingy B; // this thingy lives on the stack and will be deleted when we return from foo
  Thingy *pointerToB = &B; // this points to an address on the stack
  Thingy *pointerToC = new Thingy(); // this makes a Thingy on the heap.
                                     // pointerToC contains its address.

  // this is safe: C lives on the heap and outlives foo().
  // Whoever you pass this to must remember to delete it!
  return pointerToC;

  // this is NOT SAFE: B lives on the stack and will be deleted when foo() returns. 
  // whoever uses this returned pointer will probably cause a crash!
  return pointerToB;
}

为了更清楚地了解堆栈是什么,请从另一端来看它 - 而不是尝试理解堆栈在高级语言方面的作用,查找“调用堆栈”和“调用约定”,然后查看机器确实在您调用某个功能时会执行此操作。 计算机内存只是一系列地址; “堆”和“堆栈”是编译器的发明。


我会说:

如果可以,将它存储在堆栈中。

将它存储在堆上,如果你需要的话。

因此,更喜欢堆栈堆。 一些可能的原因,你不能在堆栈上存储的东西是:

  • 这太大了 - 在32位操作系统上的多线程程序中,堆栈的大小很小(固定的时间至少为线程创建时间)(通常只有几个兆字节),这样可以创建大量线程而不会耗尽地址对于64位程序或单线程(无论Linux)程序,这并不是一个主要问题,在32位Linux下,单线程程序通常使用动态堆栈,这些堆栈可以保持增长,直到达到堆顶。
  • 您需要在原始堆栈框架的范围之外访问它 - 这确实是主要原因。
  • 有理性的编译器可以在堆上分配非固定大小的对象(通常是编译时不知道大小的数组)。


    它比其他答案所暗示的更微妙。 根据您声明的方式,堆栈上的数据与堆上的数据之间没有绝对的分歧。 例如:

    std::vector<int> v(10);
    

    在函数的主体中,它声明了栈中十个整数的vector (动态数组)。 但由vector管理的存储不在堆栈上。

    嗯,但(其他答案显示)存储的生命周期以vector本身的生命周期为基础,这是基于堆栈的,所以它的实现方式没有区别 - 我们只能将它视为基于堆栈具有价值语义的对象。

    并非如此。 假设这个函数是:

    void GetSomeNumbers(std::vector<int> &result)
    {
        std::vector<int> v(10);
    
        // fill v with numbers
    
        result.swap(v);
    }
    

    因此,任何具有swap功能的swap函数(以及任何复杂的值类型都应该具有swap函数)可用作某种堆数据的一种可重新引用的引用,该系统保证该数据的单个所有者。

    因此,现代C ++方法是永远不会将堆数据的地址存储在裸指针变量中。 所有的堆分配必须隐藏在类中。

    如果你这样做了,你可以将程序中的所有变量看作是简单的值类型,并且完全忘记堆(除非为一些堆数据编写新的值类封装类,这应该是不寻常的) 。

    你只需保留一点特殊的知识来帮助你优化:在可能的情况下,而不是像下面这样将一个变量赋值给另一个变量:

    a = b;
    

    把它们换成这样:

    a.swap(b);
    

    因为它速度更快,并且不会抛出异常。 唯一的要求是你不需要b继续保持相同的值(它会得到a值,而这会在a = b被删除)。

    缺点是这种方法迫使你通过输出参数而不是实际的返回值从函数返回值。 但他们正在用rvalue引用修正C ++ 0x。

    在所有最复杂的情​​况下,你会把这个想法带到一般的极端,并使用一个智能指针类,例如已经在tr1中的shared_ptr 。 (虽然我认为如果你似乎需要它,你可能已经超出了标准C ++的适用范围。)

    链接地址: http://www.djcxy.com/p/2335.html

    上一篇: Proper stack and heap usage in C++?

    下一篇: Get current stack trace in Java