了解物体的构造,寿命和破坏

时间:2017-05-14 13:52:00

标签: c++

我的问题实际上是两部分的。快速前言:我正在学习C ++并且来自C#/ .NET背景。目前,我正在尝试了解对象的生命周期,下面发布的结果对我来说没有意义。我认为这可能与创建匿名实例有关吗?

问题1:处理析构函数中的所有成员是否是一个好主意,因为它可能是一个“空对象”?

问题2:如何防止这种情况发生? /如何设计我的对象以使用此功能?

问题3:这是“正确”/“正确”的方式吗?

问题4:在最后一段代码中查看评论

#include <stdio.h>

class A
{
public:
    A()
    {
        printf("Constructor A\n");
    }

    ~A()
    {
        printf("Destructor A\n");
    }
};

class B
{
public:
    B()
    {
        a = A();

        printf("Constructor B\n");
    }

    ~B()
    {
        printf("Destructor B\n");
    }
private:
    A a;
};

int main(int argc, char* argv[])
{
    B b;
    b = B();

    printf("Done");
    // Breakpoint
    /*
        Output:

        Constructor A
        Constructor A
        Destructor A
        Constructor B
        Constructor A
        Constructor A
        Destructor A
        Constructor B
        Destructor B
        Destructor A
    */
}

另一个来自我目前正在进行的项目的例子。

#include <stdio.h>

class Mesh
{
public:
    Mesh()
    {
        printf("Constructing Mesh with data %d\n", data);
    }

    Mesh(int d)
    {
        data = d;

        printf("Constructing Mesh with data %d\n", data);
    }

    ~Mesh()
    {
        printf("Destructing Mesh with data %d\n", data);
    }

private:
    int data = 0;
};

class Game
{
public:
    Game()
    {
        printf("Game constructor\n");
    }

    ~Game()
    {
        printf("Game destructor\n");
    }

    void init()
    {
        int cool_data = 3;

        mesh = Mesh(cool_data);
    }

private:
    Mesh mesh;
};

int main(int argc, char* argv[])
{
    Game game = Game();
    game.init();

    printf("");
    // Breakpoint
    /*
        Output:

        Constructing Mesh with data 0      <-- I assume this comes from the private member declaration in the Mesh class? So declaration means initialization?
        Game constructor
        Constructing Mesh with data 3      <-- Okay that's what I expected since I'm creating a new instance of the Mesh class with "3" passed in
        Destructing Mesh with data 3       <-- Why is the instance we JUST created immediately being destructed?
    */
}

1 个答案:

答案 0 :(得分:1)

在你的第一个例子中,我们看到很多构造和破坏“A”对象,如果你不熟悉C ++,这些对象似乎很神秘。你的B类有一个私人A变量“a”。首次将构造函数调用到B类时,将默认构造此对象。这是你看到的第一个“构造函数A”打印输出。下一个打印输出来自这里对A构造函数的调用:

B()
{
    a = A(); //A() calls the A constructor and returns an r-value
    printf("Constructor B\n");
}

将类A的已实例化对象“a”分配给由类A的默认构造函数调用返回的r值会导致在创建r值时打印“构造函数A”,并且“析构函数A“当r值本身被破坏时。可以通过创建复制和移动构造函数/运算符来更改这些行为,这将允许您指定这些语义的运行方式。查看此页面:http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html或一本书(C ++ 11入门书很好),了解有关这些操作的更多信息。

按照上面的逻辑,当您将创建的B对象“b”分配给B类默认构造函数的行中返回的右值时:

b = B();

构造一个必须的新B对象  1)构造一个A对象  2)创建一个A r值  3)破坏A r值  4)构造一个B对象

最后两个打印语句只是你的B对象被破坏为主要出口。 B对象被破坏,它的成员也是A对象。你的第一个问题似乎是关于这种行为。看起来你问是否应该手动破坏类成员。如果您的类为其成员分配内存,则只能在C ++中完成。例如,如果不是创建本地A对象,则B中的构造函数执行此操作:

B()
{
    a = new A();
    printf("Constructor B\n");
}
...
private:
A* a;

然后你必须在你的析构函数中释放这个A *。只要您不使用new运算符或其他方式分配新内存,C ++将为您处理所有其他释放。

你的问题2和3是关于如何防止/使用对象构造以及构造/破坏对象的给定方式是对还是错。我想指出你的0/3/5规则。这基本上处理了您应该为给定类创建的构造函数数量。这是对http://en.cppreference.com/w/cpp/language/rule_of_three规则的一个非常简单的解释,但还有许多其他在线。

你的最后一个问题与你拥有的网格类有关,以及为什么你的一个变量被破坏了。同样,这与调用构造函数返回的r值有关。基本上,当您调用网格构造函数并将其返回值分配给变量“mesh”时:

void init()
{
    int cool_data = 3;
    mesh = Mesh(cool_data);
}

网格构造函数返回一个r值,它是Mesh类的一个对象,数据值为3;将r值复制到“网格”变量中并立即销毁,将“网格”变量作为其精确副本。同样,可以通过创建适当的构造函数和运算符来更改所有这些行为。