我正在阅读Java to C++ crash course,除此之外,它还谈到了C ++中的内存管理。举例说明了必须做的事情:
Foo& FooFactory::createBadFoo(int a, int b)
{
Foo aLocalFooInstance(a, b); // creates a local instance of the class Foo
return aLocalFooInstance; // returns a reference to this instance
}
这不起作用,因为aLocalFooInstance
会留下范围并被销毁。很好,对我来说很有意义。现在作为这个问题的一个解决方案,给出了以下代码:
Foo FooFactory::createFoo(int a, int b)
{
return Foo(a, b); // returns an instance of Foo
}
我不明白:为什么第二个例子是有效的C ++代码?这两个例子中的基本问题是不一样的,即创建了Foo
的实例,它会超出范围,因此当我们从方法返回时会被销毁?
答案 0 :(得分:2)
说我们有代码
Foo FooFactory::createFoo(int a, int b)
{
return Foo(a, b); // returns an instance of Foo
}
int main() {
Foo foo = FooFactory::createFoo(0, 0);
}
区分创建的各种Foo
对象非常重要。
从概念上讲,执行过程如下:
Foo(a, b)
时,会创建一个Foo
类型的临时对象。Foo
的结果。该临时用于初始化非临时对象FooFactory::createFoo(0, 0)
。在存在复制省略和返回值优化的情况下,可以省略两个临时值。
请注意,如果函数通过引用返回,则第2步不创建新对象;它只创建一个引用。因此,在步骤3之后,所引用的对象不再存在,并且在步骤4中,初始化将从悬空引用发生。
答案 1 :(得分:1)
因为第二个示例按值返回对象,而不是通过引用返回。
第一个示例返回对对象实例的引用,第二个示例返回对象的实例。
您所展示的评论甚至明确说明了这一点。
在第一个示例中,仅返回引用,并且引用的对象将被销毁。
在第二个示例中,返回对象本身。这意味着对象“继续存在”,从某种程度上讲,它会在调用此函数的代码放置该对象的任何地方结束。
答案 2 :(得分:0)
当你返回一个实例时,你不会延长对象的生命周期,所以它会在函数的结束时被破坏,你的引用现在什么都没引用。
如果你返回一个类,那么该类被复制(除非RVO适用,这是一个完全不同的东西,效果相同)到外部该函数在被销毁之前,所以你现在拥有一个处于完美工作状态的创建对象的副本,并且可以正常使用。
答案 3 :(得分:0)
在第二个示例中,您(逻辑上)返回副本。想象一下,如果你返回一个int而不是Foo
:
int FooFactory::createInt(int a, int b)
{
return a+b;
}
你能看出这不是问题吗?
在C ++中,只要int
可移动或可复制,Foo的工作原理与Foo
相同。