假设我有一个名为Money
的课程,其中包含参数Dollars
和Cents
我可以通过以下两种方式初始化它:
我的问题是我何时应该使用(1)以及何时应该使用(2)
答案 0 :(得分:8)
尽可能使用1,必要时使用2。 “当你必须”时基本上转换为“当你创建一个生命周期不是/不能与”范围“联系在一起的对象时 - 也就是说,它必须在创建它的函数退出后保持存在。你通常想要避免这种情况,例如通过返回有问题的对象的副本,而不是在函数返回后使该对象(本身)持续。
过去,(不幸的是)没有真正坚硬的指导方针可以确保你做得尽可能好。
答案 1 :(得分:6)
第一个在堆栈上创建一个Money
对象,其生命周期在创建时的范围内。当你点击}
时它意味着超出范围并返回内存。如果要在一个函数中创建对象,请使用此选项。
第二个在堆上创建一个Money
对象,它的生命周期与你想要的一样长,即直到你delete
为止。当您希望将对象传递给不同的函数时使用此
答案 2 :(得分:3)
Money a(3,15);
在本地范围内分配Money
个对象。
Money* b=new Money(3,15);
将指针变量分配给本地作用域,并使指针“指向”驻留在免费存储中的Money
对象(假设分配成功完成,否则抛出std::bad_alloc()
)
示例1:
假设下一个场景:
Money * b = initialize();
,其中
Money* initialize()
{
Money x(2 , 15);
return &x;
}
这将失败,因为在initialize()
到达执行结束后x
被销毁,现在b
指向一个无效的位置,如果你使用了,则会调用Undefined Behavior它。所以你应该用指针
Money* initialize()
{
return new Money(2,15);
}
当您想要存储和使用大小的数组时,也会使用免费商店。
正如您在示例中注意到的那样,两者之间存在差异,那就是在本地范围x
中您不需要delete
该对象。但是在使用new
时,您必须手动执行delete x;
。否则会发生内存泄漏(占用内存空间而不再使用,因此会占用内存)。
除了这篇文章之外,请参阅Martin York对更深层次知识的回答。
答案 3 :(得分:2)
这是一个比它看起来要复杂得多的问题。简单的答案是
1)当你想要堆栈存储和作用域绑定资源管理时,当保留作用域时,将调用该对象上的析构函数并弹出堆栈中的存储。
注意不要将指针传递给调用堆栈中的其中一个作用域绑定对象(返回,输出参数),这是一种简单的段错误方法。
2)当您希望在免费商店中分配对象时,必须删除此指针,否则将发生内存泄漏。
看看shared_ptr,scoped_ptr,auto_ptr等。对于一些使#2在某些方面起作用的替代方案,如#1。
另外,请查看this question以获取有关C ++中内存管理的一些指示。
答案 4 :(得分:1)
从技术上讲,你更喜欢你从未做过(2)直接但更喜欢使用智能指针:
std::auto_ptr<Money> b(new Money(3,15)); // auto_ptr is just an example of a smart pointer
但总体问题仍然存在 当对象的生命周期不超过使用它的函数或对象时,使用(1)。当对象的生命周期延长的时间长于编译时预测的时间时,请使用(2)。
被称为自动存储持续时间对象。这意味着它会被编译器生成的代码自动创建和销毁(重要位)。
被称为动态存储持续时间对象。这意味着您有责任手动创建和销毁对象。销毁对象需要我们维护与对象关联的所有权概念,并且只允许所有者销毁它(否则我们会有多个源试图销毁对象)。为了帮助进行所有权跟踪,我们引入了拥有指针的智能指针。然后它成为智能指针的责任来完成破坏对象的实际工作。这使得使用指针构建类和函数变得更加容易。
如果你的对象很便宜,可以创建一个副本(它看起来像是这样)。然后你几乎不需要动态创建对象。将对象传递给函数或返回结果都可以非常正常地完成:
Money CalcInterest(Money const& m, double interest)
{
Money result(m.doallas * interest, m.cent * interest);
return result; // Return a copy quite happily.
}
如果你正在构建一个动态表达式,那么你可以使用智能指针来保存指针。
struct Expression
{
char op;
std::auto_ptr<Money> lhs;
std::auto_ptr<Money> rhs;
};
std::auto_ptr<Expression> getExpressionFromUserInput()
{
std::auto_ptr<Expression> result(new Expressions(/* etc */);
return result;
}
答案 5 :(得分:1)
表格1最简单;尽可能使用它。
表单2会为您购买以下内容:
Money* b
应指向GoodMoney
还是BadMoney
表单2引入了可能性或资源泄漏,因为使用new
创建的对象最终必须使用delete
销毁。正如其他人所说,使用智能指针可以消除或减轻这个问题。
简而言之,当您需要上面列出的内容之一时,请使用表单2,然后将其放入智能指针中;否则使用表格1。
答案 6 :(得分:0)
完全不同。
您有一个在堆栈上构建的对象。它的生命范围将持续到代码块。
您在堆中分配的某个内存地址处初始化了一个对象。在致电delete b
之前,它不会被销毁。
答案 7 :(得分:0)
通常,当对象具有有限的生命周期(在块的上下文中)时,您将使用表单1;当对象必须在声明的块中存活时,使用表单2.让我举几个例子:
int someFunc() {
Money a(3,15);
...
} // At this point, Money is destroyed and memory is freed.
或者,如果你想让对象在函数中存活,你可以使用new,如下所示:
Money *someOtherFunc() {
Money *a = new Money(3,15);
....
return a;
} // we have to return a here or delete it before the return or we leak that memory.
希望这有帮助。
答案 8 :(得分:-3)
如果需要指向对象的指针,则应使用选项2;如果需要值,则应使用选项1。