何时从内存中删除匿名对象以及建议何时使用它们

When does the anonymous objects get deleted from memory and when it is recommended to use them?

本文关键字:何时使 对象 内存 删除 何时      更新时间:2023-10-16

我是 c++ 的新手,我试图了解构造函数和析构函数以及一些关于内存管理的知识。在下面的代码中,除了

1.MyClass((.disp((; 2.新的我的班级; 3.新我的班级(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 destructort"<<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;
} 

"匿名对象"不是一个标准术语,它是一个描述性术语。我会把它解释为一个没有名字的对象。具有名称的对象称为变量或数据成员。

  1. 在表达式 MyClass().disp() 中,您将在类 MyClass临时对象上调用成员函数disp。临时对象的生存期延长 [1] 到完整表达式的末尾。如果我没记错的话,这在C++标准中被称为全表达式

  2. new表达式new MyClass为新的MyClass对象分配内存,并在该内存块中创建新的MyClass对象。表达式生成指向新对象的指针。可以将该指针存储在变量中,并在后面的delete表达式中使用它来销毁对象并释放其内存。

  3. 表达式new MyClass(300)是相同的,只是为MyClass构造函数提供了一个参数。new -expression 语法还提供了用于指定分配操作参数的表示法。但这更高级,很少需要,无论如何,作为初学者,您应该优先不要使用原始newdelete,而是使用标准库容器和字符串。

如果new没有相应的delete,则对象一直存在到程序执行结束。如果这是一台带有操作系统的计算机,则操作系统将回收内存。但是,OS 对C++对象一无所知,因此不会调用对象析构函数,因此不会执行析构函数中指定的清理。

你问new哪里有用。通常,当对象的所需生存期不适合范围(局部自动变量的嵌套生存期(和/或需要动态大小对象时。使用 new 来控制生命周期对于高效可移动的对象(如 C++11 及更高版本(来说问题不大,对于动态大小,优先使用容器(如 std::vector(和字符串(如 std::string(。

[1] 更一般地说,临时对象可以直接绑定到局部引用,在这种情况下,其生存期延长至引用的生存期,即在封闭块之外。

通常,您会在堆栈上分配对象,因为它更快,并且不需要删除它。

但是,如果要返回指针,则必须在堆上分配它。例如

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++代码中的常见习惯用法。

除了干杯和hth。 - 阿尔夫的回答,但是我会添加这个...

如果您真的想要并且必须在堆上创建一个类 Bar 的临时对象,只需使用 std::make_shared (C++11( 或 std::make_unique (C++14(....

例:

std::make_unique<Bar>()->foo()
std::make_shared<Bar>()->foo()

上面创建了Bar并调用它的方法foo()Bar 的析构函数在 foo() 完成后被调用,并且总是删除其关联的内存。

可以像旧C++那样编写一个简单的类和函数,但由于可变参数模板和完美的转发,它不能是通用的

免费建议:避免任何需要上述情况的情况...即使是下面的代码(据说比堆更有效(在代码审查中通常也会皱眉

Bar().foo()

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;
}

有时可能有用