代码之家  ›  专栏  ›  技术社区  ›  VirusEcks

C++内存分配

  •  3
  • VirusEcks  · 技术社区  · 14 年前

    使用C++时, 如果有课程:

    class MyClass
    {
        char memory1bye;
        int memory4bytes;
        int another4bytes;
    };
    

    这个类在内存中总共使用了9个字节,所以如果我执行以下操作:

    MyClass *t1;
    

    这将给我一个类的可用地址,但它会分配9个字节吗?它会调用默认构造函数吗? 或者我需要把这9个字节malloc到类中? 如果我打电话给你:

    t1 = (MyClass *)new MyClass;
    

    9 回复  |  直到 14 年前
        1
  •  2
  •   Donal Fellows    14 年前
    1. 正如许多人所说的那样 MyClass 依赖于实现。在这种情况下,因为类没有方法,所以基本上已经有了一个结构,所以可以对大小进行一些合理的猜测。在没有任何异常编译器标志的普通现代32位机器上,结构的大小将是12字节;这是因为在当前体系结构中,字段默认与4字节边界对齐。

      在64位机器上,它可能更大,但如果它大于24字节(即每个字段8字节对齐),我会有点惊讶。我不认为任何东西会对字段使用大于8字节的对齐方式,除非明确要求这样做,而且对字段使用更大的对齐值也没有多大意义,因为内存分配函数本身通常具有8字节对齐方式。

      这个 只有 真正知道任何东西大小的方法是使用 sizeof(MyClass) . 你几乎不需要在C++中使用它,因为 new 操作员知道这一点,并为您分配所需的空间量。如前所述,记住 (除 char )是不可携带的,即使他们实际上没有免费的变化。

    2. MyClass *t1; 不分配任何东西。它只是给你一个地方来存储一个对象的地址(特别是一个 在类或结构定义中。如果不打算在变量中放入地址,那么最好显式地将其初始化为 NULL 所以它至少指向一个确定的而不是一个对象。

    3. 你的 t1 = (MyClass *)new MyClass; 新的 t1 = new MyClass; 够了。

    4. 如果 t1 ,则不会有任何泄漏。

      记住,地址不会泄漏;对象会泄漏。

      您可以通过在堆栈上创建对象(使用 MyClass t1;

        2
  •  14
  •   Björn Pollex    14 年前
    1. 不要假设数据类型的大小,它们依赖于实现。
    2. MyClass *t1 undefined behavior .
    3. t1 = (MyClass *)new MyClass; 在堆上分配内存并创建一个新对象。如果此内存没有使用 delete ,将出现内存泄漏。而且,你不需要演员, t1 = new MyClass();

    编辑: 关于分配。

    MyClass *t1 = NULL; 
    

    声明指向 MyClass -对象,但它不创建对象。此指针初始化为指向 0 . 现在当你这么做的时候

    t1 = new MyClass();
    

    接线员 new 创建的新实例 类名 t1 . 现在可以通过 :

    t1->doStuff();
    

    MyClass *t2 = t1;
    

    现在 t2 指向同一个对象。处理完对象后,只需执行以下操作:

    delete t1;
    

    ( delete t2 会有同样的效果)。现在对象被销毁了,但是指针仍然指向同一个地址(这不再安全)。做

    t2->doStuff();
    

    之后 删除 调用未定义的行为。如果我们回到删除之前,请考虑以下问题:

    t1 = NULL;
    t2 = NULL;
    

    在上面。这会造成内存泄漏。希望这能让你对正在发生的事情有所了解。现在忘掉这一切,读一读 RAII

        3
  •  4
  •   Jim Brissom    14 年前

    仅仅声明一个指针不会分配内存来保存类,也不会调用构造函数。您必须调用new操作符来实际分配内存并提供对象初始化。另外,不需要强制转换new的返回类型。

    哦,我还必须告诉你,在C++中,你几乎应该总是寻找其他方式来比手动管理内存,这些容器类(STD::vector,STD::DeQuoGuffer-like)和智能指针,这两个都使得管理内存更少痛苦。

        4
  •  2
  •   Tony Delroy    14 年前
    MyClass* t1;
    

    这实际上并没有为MyClass对象分配内存。您的变量只是一个指针,有可能跟踪MyClass对象的内存地址,但是还没有创建这样的对象,并且指针没有被设置为指向任何地方。

    (当然,会为指针本身分配一些内存,但如果该语句位于函数内部,则内存在堆栈上,否则为全局内存)

    t1 = (MyClass*)new MyClass;
    

    MyClass t;  // who needs a pointer?
    

    那你就不用去想那些记忆了。缺点是对象只有在离开创建它的作用域时才存在,如{和}的嵌套所示。

    t1 = new MyClass;
    

    过一段时间,你也会想删除t1。

    MyClass的实际大小可能不是9字节。。它取决于编译器,可能是编译器命令行标志、编译器版本、目标内存模型、操作系统等的函数。。

        5
  •  2
  •   Donal Fellows    14 年前

    除了其他一些答案外:

    1. 班级的“规模”受许多因素的影响:

      • 这个 vtable
      • 成员变量的内存对齐要求


    2. 虽然不需要强制转换,但它也是坏的C++风格。不喜欢使用C样式的CAST,但使用C++中的其他、更安全(或至少更明确)的一种转换方式:

      • dynamic_cast<type>()
      • static_cast<type>()
      • reinterpret_cast<type>()

    有关更多信息,请参阅 C++ Reference Guide - New C++ Cast Operators

        6
  •  1
  •   Vintharas    14 年前

    如果你这样做

    MyClass *t1;
    

    您只是声明了一个指向类MyClass的指针。你没有真正分配任何内存。为了创建该类的实例,您可以使用以下任一方法:

    MyClass t2;                  // this calls a default constructor implicitly
    MyClass t3 = MyClass();      // this also calls a default constructor explicitly
    MyClass *t4 = new MyClass;   // calls default constructor implictly
    

    前两个声明使用自动存储,而最后一个声明使用动态存储。如果为类定义参数化构造函数,则声明如下:

    MyClass t5(arg1, arg2, arg3);
    MyClass t6 = MyClass(arg1, arg2, arg3);
    MyClass *t7 = new MyClass(arg1, arg2, arg3);
    
        7
  •  1
  •   Chubsdad    14 年前

    - MyClass *ptr 只声明一个指向“MyClass”类型的指针。它还没有指向任何类型为“MyClass”的对象。如果它是全局的,它将被初始化为零,否则如果这样的指针是本地的(例如函数作用域),它将被取消初始化。

    MyClass m; 
    ptr = &m;       // this does not create any new object(no constructor runs)
    

    或者

    MyClass *ptr;
    ptr = new MyClass();  // This new expression, allocates memory large 
                          // enough to hold a 'MyClass' object, initializes
                          // the object by running it's constructor
    
    delete ptr;           // delete the MyClass object by running it's 
                          // destructor, return the allocated memory back
                          // to the implementation
    

    -如果在执行新操作后不删除指针ptr,那么肯定是内存泄漏

        8
  •  1
  •   vulkanino    14 年前

    不要假设MyClass使用9字节,这取决于机器和编译器!

    MyClass*t1;

    那会给你一个有用的机会 指针 ,但尚未分配容纳类的空间。所以前两个问题的答案是否定的。

    是的,如果你想使用指针,你必须为自己的类分配空间。当然,您可以通过在堆*上创建MyClass来消除内存分配:

    MyClass t1();

    • 我的意思是:堆叠。
        9
  •  0
  •   Scott Langham    14 年前

    类不能为9字节。如果编译器通过填充结构使其更好地适应计算机体系结构,那么它可能会更多。

    MyClass*t1;没有提供可用的地址。它是一个未初始化的指针,指向一个随机的内存位置,不知道该地址可能是什么。它不会为您分配任何空间来存储MyClass实例,也不会调用构造函数。我建议您在定义指针时初始化它们:

    MyClass *t1 = 0;   // use 0, NULL, or null_ptr
    

    您需要为类保留空间并调用构造函数新的'为你做这两件事。

    MyClass *t1 = new MyClass();
    

    别忘了你需要一个'删除'来匹配每一个新的,否则你会写一个内存泄漏。