想问一下功能上的区别;也许要求一个示例场景,我应该从下面的主要方法中的选项之一中进行选择:
#include <iostream>
using namespace std;
class A{
private:
int x, y;
public:
A(int, int);
};
class B{
private:
int *x, *y;
public:
B(int, int);
~B();
};
A:: A(int x, int y){
this->x = x; this->y = y;
}
B:: B(int x, int y){
this->x = new int(x);
this->y = new int(y);
}
B:: ~B(){
delete this->x;
delete this->y;
}
int main(){
int x = 0, y = 0;
A* objA = new A(x, y); // line 1
B objB1(x, y); // line 2
B* objB2 = new B(x, y); // line 3
delete objA;
delete objB2;
return 0;
}
我知道主方法 B objB1(x, y)
中的第二个声明明显不同于其他 2 个,但是有人可以解释标记为 1 的行中构造函数之间的功能差异和 3?这两个声明中是否有任何不良做法?
谢谢
NAX
更新
首先,我感谢大家给出的所有答案,我真的得到了一些很好的见解。我已经编辑了上面的代码,因为一些答案指出我没有删除我使用的对象,这是公平的,但这不是我的问题的目的。我只是想深入了解创建类的不同方法之间的功能差异。感谢所有针对这一点的人。我仍在通读答案。
最佳答案
"The functional difference..."
在第 1 行,您通过使用 new
关键字在堆 上分配了一个类型 A 的对象。在堆上,为 objA
指向的对象分配空间,这意味着在堆上连续创建 2 个 int
,符合您的 ivar 定义。
在第 2 行,您在堆栈 上创建了一个 B 类的新对象。当它超出范围时,它将自动调用其析构函数。但是,当 B 被分配时,它将分配两个 int 指针(不是 int)的空间,这将依次分配在 heap 上,正如您在 B 中指定的那样构造函数。当 objB1
超出范围时,指针将被析构函数成功删除
。
在第 3 行,您在堆 上创建了一个 B 类的新对象。因此,在堆上为两个 int 指针(不是 int)分配空间,然后这些 int 又通过使用 在堆上的其他地方分配 new
关键字。当您delete
objB2
时,析构函数被调用,因此两个“其他地方的整数”被释放,然后您在 objB2
的原始对象也被释放从堆中释放。
根据 WhozCraig 的评论,类 A
绝对是您在示例中显示的两个类定义中的首选。
编辑(评论回复):
WhozCraig 的链接基本上强烈反对使用原始指针。事实上,是的,我同意,第 2 行纯粹基于内存管理是首选,因为 B
在技术上管理自己的内存(尽管它仍然使用原始指针)。
但是,我通常不喜欢(过度)在类内部使用 new
,因为 new
比等效堆栈(或 >non-new
) 分配。因此,我更喜欢 new
整个类,而不是单个组件,因为它只需要一个 new
调用,而且所有的 ivar 都分配在堆中。 (更好的是,placement new
,但这远远超出了这个问题的范围)。
总结起来:
第 2 行(类 B
)在内存管理的基础上是首选,但比那更好的是:
A objAOnStack(x, y); // Avoids heap altogether
第 1 行是最好的,前提是你将它包装在一个智能指针中,例如 std::shared_ptr
或 std::unique_ptr
或类似的东西。
如果没有智能指针包装器,实际上不应该考虑第 3 行(无论如何,回避嵌套的 new
通常会提高性能)。
关于C++:删除对象还是删除成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15331568/