首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >了解物体的建造、寿命和销毁情况

了解物体的建造、寿命和销毁情况
EN

Stack Overflow用户
提问于 2017-05-14 13:52:00
回答 1查看 147关注 0票数 1

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

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

问题2:如何防止这种情况?/如何设计对象以处理此特性?

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

问题4:参见最后一段代码中的注释

代码语言:javascript
复制
#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
    */
}

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

代码语言:javascript
复制
#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?
    */
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-14 16:23:50

在您的第一个示例中,我们看到许多"A“对象的构造和破坏,如果您不熟悉C++的话,这些东西看起来很神秘。您的B类有一个私有的A变量"a“。当您第一次调用B类的构造函数时,此对象是默认构造器。这是你看到的第一个“构造函数A”打印出来的。下一个输出来自对A构造函数的调用:

代码语言:javascript
复制
B()
{
    a = A(); //A() calls the A constructor and returns an r-value
    printf("Constructor B\n");
}

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

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

代码语言:javascript
复制
b = B();

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

最后两个print语句只是您的B对象作为主出口被销毁。B对象被破坏,它的成员A对象也被破坏。你的第一个问题似乎是关于这种行为。看起来您在问是否应该手动销毁类成员。只有在您的类为其成员分配内存时,才会在C++中这样做。例如,如果B中的构造函数没有创建本地A对象,而是执行了以下操作:

代码语言:javascript
复制
B()
{
    a = new A();
    printf("Constructor B\n");
}
...
private:
A* a;

那你就得在你的破坏者中释放这个A*。只要您不使用新运算符或其他方式分配新内存,C++将为您处理所有其他的去分配。

您的问题2和问题3是关于如何防止/使用对象构造,以及构造/销毁对象的给定方法是否正确。我想指出的是0/3/5的规则,这基本上涉及到你应该为一个给定的类创建多少构造函数。这是对规则three的一个非常简单的解释,但是网上还有很多其他的解释。

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

代码语言:javascript
复制
void init()
{
    int cool_data = 3;
    mesh = Mesh(cool_data);
}

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43964667

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档