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

时间:2016-02-07 13:33:26

标签: c++

我是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;

} 

4 个答案:

答案 0 :(得分:3)

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

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

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

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

  4. 如果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_uniquevariadic 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;
}

有时可能有用