我是c ++的新手,我试图理解构造函数和析构函数以及一些关于内存管理的内容。在下面的代码中,除了
之外,一切正常1.MyClass()DISP(); 2.new MyClass; 3.new MyClass(300);
1)我想知道将所有这三个称为匿名对象是否正确。 2)对于MyClass(),我知道这会创建一个对象并立即销毁它,因此没有内存问题。 但是对于新的MyClass(),析构函数永远不会被调用。我也明白,因为这是在堆上我将必须显式删除该对象。但在这种情况下我该怎么办呢? 如果不可能,程序执行后该内存何时可以释放? 3)此外,我想知道这种类型的对象创建(新的MyClass)可能有用的场景。
#include<iostream>
#include<conio.h>
using namespace std;
class MyClass
{
private:
int num;
public:
MyClass()
{
cout<<"no-arg constructor"<<endl;
}
MyClass(int num)
{
this->num=num;
cout<<"one param constructor"<<endl;
}
~MyClass()
{
cout<<"inside destructor\t"<<num<<endl;
}
void disp()
{
cout<<num<<endl;
}
};
int main()
{
MyClass m1;
MyClass m2(200);
MyClass *m3=new MyClass;
MyClass *m4=new MyClass(400);
MyClass().disp();
new MyClass;
new MyClass(300);
delete m4;
delete m3;
return 0;
}
答案 0 :(得分:3)
“匿名对象”不是标准术语,它是一个描述性术语。我会把它解释为没有名字的对象。具有名称的对象称为变量或数据成员。
在表达式MyClass().disp()
中,您在类disp
的临时对象上调用成员函数MyClass
。临时对象的生命周期将 [1] 扩展到完整表达式的末尾。如果我没记错的话,在C ++标准中,它被称为完整表达式。
new
- 表达式new MyClass
为新的MyClass
对象分配内存,并在该内存块中创建新的MyClass
对象。该表达式生成一个指向新对象的指针。您可以将该指针存储在变量中,并在稍后的delete
表达式中使用它来销毁该对象并释放其内存。
除了为new MyClass(300)
构造函数提供参数外,表达式MyClass
是相同的。 new
- 表达式语法还提供了一种表示分配操作的参数的表示法。但是这样更高级,很少需要,无论如何,作为初学者,你应该优先使用原始new
或delete
,而是使用标准库容器和字符串。
如果delete
没有对应的new
,那么该对象将一直存在,直到程序执行结束。如果这是带有操作系统的机器,那么操作系统将回收内存。但是,操作系统对C ++对象一无所知,因此不会调用对象析构函数,因此不会执行析构函数中指定的清理。
你问new
在哪里有用。通常,当对象的期望生命周期不适合作用域(本地自动变量的嵌套生存期)时,和/或需要动态大小对象的情况。使用new
控制生命周期对于高效移动对象来说不像C ++ 11及更高版本那么严重,动态大小优先使用std::vector
等容器和std::string
之类的字符串。
[1] 更一般地说,临时对象可以直接绑定到本地引用,在这种情况下,它的生命周期延长到引用的生命周期,即从封闭块开始。 功能
答案 1 :(得分:0)
通常,你会在堆栈上分配对象,因为它更快,你不需要删除它。
但是,如果要返回指针,则必须在堆上分配它。例如
int *foo(int n)
{
int *pn = new int(n);
return pn;
}
现在调用者负责释放内存。
int main()
{
try {
int *ptr = foo(6);
// use ptr
delete ptr;
} catch (std::bad_alloc &ba) {
std::cerr << ba.what() << '\n';
}
}
您的错误是不存储new
的返回值。如果不存储返回值,您将如何使用内存?你将如何释放它?这就像支付电影票,但然后扔掉了。
您的计划有其他错误。 main
必须返回int
,而不是void
。使用标准getchar
函数代替getch
也是一个更好的主意。
我还在代码中添加了异常处理,因为new
在无法分配时抛出异常。将整个main
函数代码包装在try
块中是C ++代码中常见的习惯用法。
答案 2 :(得分:0)
除Cheers and hth. - Alf的答案外,我还会添加此内容......
如果您非常想要 并且 在堆上创建类\n
的临时对象,只需使用{{ 3}}(C ++ 11)或std::make_shared(C ++ 14)......
示例:
Bar
以上内容创建了std::make_unique<Bar>()->foo()
std::make_shared<Bar>()->foo()
并调用了它的方法Bar
。在foo()
完成后调用Bar
的析构函数,并且总是将其关联的内存删除....
可以编写一个简单的类和函数,就像在较旧的C ++中一样,但由于std::make_unique和variadic templates
,它不可能是通用的免费建议:避免任何需要上述内容的情况......即使下面的代码(据说比堆更有效)通常在代码审查中也不赞成
foo()
答案 3 :(得分:0)
3)仍然可以通过this
引用新对象,因此您可以执行(1)
或(2)
,或者仅将指针作为参数传递或从函数(3)
返回。
#include <vector>
#include <iostream>
class MyClass;
std::vector<MyClass*> vec;
class MyClass {
public:
// (1)
MyClass() { std::cout << 'c'; vec.push_back(this); }
~MyClass() { std::cout << 'd'; }
// OR (2)
MyClass* doSmth() { /* do some work; */ return this; }
void destroy() { delete this; }
// OR (3)
static void doAndDelete(MyClass* p)
{
// do smth
delete p;
}
static MyClass* creator() { return new MyClass; }
};
int main() {
// (1)
new MyClass;
for (auto x : vec)
delete x;
vec.clear();
// OR (2)
(new MyClass())->doSmth()->destroy();
// OR (3)
MyClass::doAndDelete(new MyClass);
MyClass* p = MyClass::creator();
delete p;
}
有时可能有用