c++中通过指针初始化

Initializing by pointer in c++

本文关键字:指针 初始化 c++      更新时间:2023-10-16

假设我有一个类MyClass。现在我想使用另一个类Animals,我可能会这样做。

class MyClass
{
public:
    MyClass();
private:
    Animals animals;
};

但是我也可以这样做:

class MyClass
{
public:
    MyClass();
private:
    Animals* animals;
};

,然后在构造函数中初始化类:

animals = new Animals();

这两种不同的方法有什么不同,哪一种更好,为什么?在我的使用中,Animals只能在MyClass中使用。我的问题主要是关于性能内存,我的意思是通过指针初始化是否需要更多的资源?

如果您考虑如何在类中管理内存,那么应该很清楚。当您在类中声明Animals animal时,则在类的内存占用中为animal保留空间。但是当你声明Animals* animal时,在你的类的内存占用中只保留一个指向Animal的指针。

都不是更好的,因为这取决于你的情况。如果您总是要创建一个动物并且MyClass拥有它,那么使用第一种方法,因为它只需要一个内存分配。如果animals经常是空的,并且内存是一个问题,那么您可能需要使用第二种方法。

顺便说一下,如果您使用的是c++ 11或以上版本,您可能需要考虑使用std::unique_ptr<Animal>作为第二种情况。

如果animals对象的唯一存在依赖于MyClass对象,则使用包含:

class MyClass
{
public:
    MyClass();
private:
    Animals animals;
};

如果animals的存在是独立的,但是MyClass想要与它保持关联,那么使用指针:

class MyClass
{
public:
    MyClass();
private:
    Animals * animals;
};

选择取决于对象所有权模型。

有许多考虑因素。

在包含方法中,animals的内存与MyClass对象一起分配。它们总是在一起,MyClass完全拥有 animals

在指针方法中,它们是两个独立的内存块,需要分别分配。这是一个没有任何所有权的协会。在MyClass的整个生命周期中,可能会发生多种情况:

  • myclass不关联任何Animals,即animals = nullptr
  • myclass可能在不同的时间关联到不同的Animals,即animals = a1; /* ... */; animals = a2;

而且多个对象,无论是MyClass对象还是其他类型的对象, may hold the same动物的指针。

如果animals对象被销毁,那么这些对象就有使用过期指针的风险,因此需要一些机制来避免这种情况。

使用指针方法,可以使用运行时多态性,这在包含方法中是不可能的。例如

void MyClass::setAnimal(Animal * a) {
  animal = a;
}
Animal * a1 = new Lion;
Animal * a2 = new Tiger;
MyClass x1;
x1.setAnimal(a1);
MyClass x2;
x2.setAnimal(a2);

从设计的角度来看,MyClass是一个Animal的容器。在第一个例子中,您总是有一个Animal。在第二个示例中,您可能有也可能没有Animal

例如,如果你有一只鸟的笼子,你的第一个笼子里总是有一只鸟,它不能空着,但第二个例子你可能有也可能没有鸟。

在数据库中称为Cardinality(0,1)。您可以将其想象为具有一个或零个元素的Animals的集合(即使您没有数组)。

第二个方面是,在第一个例子中,你总是有相同的Animal,你不能自由地传递它,Animal的生命周期完全取决于容器。第二个示例允许将Animal移动到一个新的容器中,或者将相同的Animal放在两个不同的容器中,并将Animal的生命周期与容器解耦。

然后,在c++中,你必须考虑内存分配和所有权,我们通常使用智能指针来释放Animal.