在堆或堆栈上创建的类的本地变量是否未声明为指针?

时间:2015-05-09 23:03:29

标签: c++

采取以下措施:

A a;

class B; // No content for brevity

class A
{
public:

    A()
    {
         b.SetTitle("hi");
    }

private:

    B b;

}

int main()
{
    return 0;
}

这里的问题是在b内声明的A是在堆上还是在堆栈上声明的。

如果在堆上,这是否意味着它会被自动删除,或者我也必须删除它吗?

附带问题:

这就是我原本在做的事情,但我认为我有点愚蠢,因为我不得不一直宣称所有的东西都是新的...如果以上是在堆栈上,我想这不是那么愚蠢吗?

A a;

class B; // No content for brevity

class A
{
public:

    A()
    {
         this->b( new B() ); // I don't have C++ 14 :( so i can't do make_unique
         b->SetTitle("hi");
    }

private:

    unique_ptr<B> b;

}

int main()
{
    return 0;
}

2 个答案:

答案 0 :(得分:10)

在固定的内存块中,它仍然可以是或者甚至(如Thomas Matthews在下面指出的那样)。在这种情况下,您可以将其视为“A内部”。如果你把A放在堆上它就在堆上。如果在函数顶部分配“A”,比如说,它位于堆栈上(但在A中)。

这样写它是A的一部分,它的生命周期与A有关。你只需要担心管理A。

答案 1 :(得分:0)

代码示例:Stack Vs堆。

// Not a proper class but used for demonstration purposes
class SomeClass {
private:
    int x;
    int* ptr;

public:        
    SomeClass() {
        // Both On x and ptr are on the stack when this constructor is defined and used.
        x = 10; 
        ptr = &x;
    } 

    SomeClass() { 
        // x is on the stack but ptr is on the heap and delete needs to be called to release the memory.
        x = 10;
        ptr = new int;
    }          
};

void someOtherFunction() {
    SomeClass a;  // on the stack relative to this function
    SomeClass* ptr = nullptr; // ptr is on the stack and is initialize to null.
    ptr = &a; // Still on the stack and ptr stores the address of (a).  

    ptr = new SomeClass(); // Now ptr lives on the heap and delete needs to be called to release its memory.         
}

最初(ptr)没有存储在其中的地址,因为我们在声明它时将其初始化为nullptr。它存储在堆栈中,此时(ptr)的地址具有一个地址,该地址是堆栈存储器寻址的一部分。现在我们将(a)的地址分配给(ptr); (ptr)仍在堆栈中,(a)在堆栈上,(a)的地址存储在(ptr)中。

一旦我们设置(ptr)= new SomeClass(),此时编译器会将内存与此类对象的大小放在一起,并将堆中的随机地址保存到(ptr)中。 (ptr)本身仍然在这个函数的堆栈上,但是(ptr)现在存储的内存地址来自堆。 (ptr)的内容可以在此函数的范围之外访问,但需要通过此函数返回类型或通过引用返回其中一个参数来返回。

另一个词(ptr)的地址在这个函数中不会改变,它保持不变,因为变量(ptr)本身仍然存在于堆栈中,它是指针变量保存的,从堆栈内存地址变为使用new时的堆内存地址。

为了演示这个在main()中运行此代码并查看结果;这仍然适用于其他函数和类结构对象。

#include <iostream> 

int main() {
    int a = 10;
    int* ptr = nullptr;
    std::cout << "Memory Address that ptr is pointing to: " << ptr << std::endl;
    std::cout << "Memory Address of ptr: " << &ptr << std::endl;
    // std::cout << "What is stored in the variable at this memory address: " << *ptr << std::endl; // This can not be called program will crash,
    // ptr can not be dereferenced for it is not pointing to anything
    std::cout << std::endl;

    ptr = &a;
    std::cout << "Memory Address that ptr is pointing to: " << ptr << std::endl;
    std::cout << "Memory Address of ptr: " << &ptr << std::endl;
    std::cout << "What is stored in the variable at this memory address: " << *ptr << std::endl;
    std::cout << std::endl;

    ptr = new int;
    *ptr = 12;
    std::cout << "Memory Address that ptr is pointing to: " << ptr << std::endl;
    std::cout << "Memory Address of ptr: " << &ptr << std::endl;
    std::cout << "What is stored in the variable at this memory address: " << *ptr << std::endl;
    std::cout << std::endl;

    delete ptr;

    return 0;
}

正如您所看到的,(ptr)的内存地址没有变化,更改的是(ptr)中存储的内存地址。现在,如果在另一个指向(ptr)的指针上使用new,则(ptr)的地址可能会改变。

现在,当您在类类型上调用new并将堆内存地址存储到该类型的指针中时,内存地址是类对象所在的位置,因此在这种情况下,属于此类的任何内容都在堆上。

Globals&amp;静态变量:

  • Globals - Globals列在(程序文件命名空间)*中,可以在声明的文件中的任何位置访问,并具有应用程序的生命周期。

  • 静态局部变量与全局变量类似,只是它们只能在声明它们的函数中访问,并且每个应用程序运行时只会初始化一次。它们具有应用程序的生命周期。

  • 类的静态成员变量与常规静态变量的行为类似,但它们没有与之关联的(this)指针。它们对于声明它们的函数是可见的,它们在每个应用程序运行时初始化一次,并且它们具有应用程序运行时的生命期或者不再存在该类对象的实例。

(*)不知道技术名称,但根据全局变量及其内存行为的方式使用程序文件命名空间是有意义的。 - 我很少使用全局变量!

以下是一些参考链接。