在C++中,创建任何一个对象(即使我们创建的是一个没有任何成员变量的对象)时,需要占用一定的内存空间。
应用程序会将可用的内存(排除源代码运行的内存等)分出两个部分:栈(stack)和堆(heap)。所以——在C++中创建对象有两种方式:在栈上创建对象和在堆上创建对象。
在栈上创建的对象,有一个自动的生命周期,他们的生命周期由它声明的作用域所决定,换言之,只要变量超出了其作用域,该对象的内存就被释放了。
在堆上创建对象则不同。在堆上创建的对象会一直待在那里,直到你决定把它释放,空闲出其对应的内存。
—— "talk is cheap, show me the code."——
#include<iostream>
#include<string>
using String = std::string;
class Person
{
private:
String m_Name;
public:
Person() :m_Name("Unknown") {}
Person(const String& name) :m_Name(name) {}
const String& GetName() const { return m_Name; }
};
假设有Person这么一个类,有私有成员变量m_Name,公共方法GetName。其中的初始化列表等知识点后续文章会说明,暂时不影响阅读代码。
在栈上创建对象personOnStack。
int main()
{
{
// 在栈上创建对象
// 可以写为 Person personOnStack = Person("person1");
Person personOnStack("person1");
// 打印名字 person1
std::cout << () << std::endl;
} // 当代码运行到此行时,personOnStack将被回收
}
在堆上创建对象personOnHeap。
int main()
{
{
// 在堆上创建对象 关键词 new
Person *personOnHeap = new Person("person2");
}
// 打印名字 person1
std::cout << personOnHeap->GetName() << std::endl;
// 在堆上分配的对象要手动释放内存
// 即 new 和 delete一起使用
delete personOnHeap;
return 0;
}
让我们来“亿丢丢”难度(涉及到C++指针部分,所谓指针,其本质就是一块内存地址)——
int main()
{
// 创建 Person 类型的指针
Person *p1, *p2;
{
// 在栈上创建对象
// 可以写为 Person personOnStack = Person("person1");
Person personOnStack("person1");
// 在堆上创建对象 关键词 new
Person *personOnHeap = new Person("person2");
/* p1指针指向 personOnStack 所在的内存地址
* 在大括号之后 personOnStack 将被回收
* 在大括号之后将获取不到 m_name = person1 的对象
*/
p1 = &personOnStack;
/* personOnHeap赋值给p2
* 在大括号之后 personOnHeap不会被回收
* 在大括号之后将获取到 m_name = person2 的对象
*/
p2 = personOnHeap;
}
// 打印结果为空
std::cout << p1->GetName() << std::endl;
// 打印名字 person2
std::cout << p2->GetName() << std::endl;
// 在堆上分配的对象要手动释放内存
// 即 new 和 delete一起使用
delete p2;
// 此处不需要delete p1的原因?
return 0;
}
如上代码所示,当代码运行到main函数中的大括号后,personOnStack对象被释放,所以p1获取到的m_Name为空;而在堆上创建的,personOnHeap对象没有被释放,所以p2能够正常获取m_Name。
最后,p1不需要delete的原因——main函数中的大括号之后,personOnStack对象被释放,所以personOnStack对象的地址也被释放,p1指针不需要被delete。
今天有关在C++中创建对象的内容就到此结束啦,希望对大家有所帮助。