从C ++中的函数返回一个对象:它的过程和性质

问题描述 投票:0回答:2

关于从函数返回一个对象我很困惑。例如:

class A
{
public:
    ~A(){}
};

A find()
{
    ...
    A a;
    return a; 
}

它是通过引用还是通过值返回“a”?此外,“查找”首先删除“a”,然后先返回或返回,然后删除“a”?

c++
2个回答
1
投票

The easy part: Does it return "a" by reference or by value?

A find()
{
    ...
    A a;
    return a; 
}

按值返回。

The hard part: Moreover, does "find" delete "a" first, then return or return first, then delete "a"?

从技术上讲,a的副本被构建,a被销毁并且副本被返回。我在C ++标准中找不到任何指定这些操作的特定顺序的东西,但有些逻辑暗示。显然你破坏后无法复制。

我怀疑这是未指定的,以允许C ++实现支持各种各样的calling conventions

注意:这意味着返回的对象必须是可复制的。如果复制构造函数被删除或无法访问,则无法按值返回。

无法确定返回或破坏是否是第一个。这应该没关系,如果你正在设计一个程序,那么就要动摇你的头脑。

Caveat

然而,在实践中,现代优化编译器将尽其所能避免在Return Value Optimization的全名下使用各种方法进行复制和销毁。

请注意,这是一种罕见的情况,允许As-If Rule被违反。通过跳过复制构造和破坏,可能不会发生一些副作用。

另请注意,即使消除了复制的需要,对象仍必须是可复制的。

Sidenote:

A & find()
{
    ...
    A a;
    return a; 
}

将返回一个参考,但这是一个非常糟糕的主意。 a具有由函数确定范围的自动存储持续时间,并将在返回时销毁。这会给调用者留下一个dangling reference,这是对不再存在的变量的引用。

为了解决这个问题,

std::unique_ptr<A> find()
{
    ...
    auto a = std::make_unique<A>();
    return a; 
}

但是你会发现,使用现代编译器,在大多数情况下,这并不比按值返回更好。


2
投票

在您的函数中,您将返回一个值,而不是引用。

A find();

返回类型是A。是值,a的副本将返回。

为了返回引用,您应该按如下方式编写函数。

A& find();

返回类型A&表示对A的引用。但是您的函数体应该相应地更改,以便返回有效的引用。

使用当前实现,您将在函数内创建对象a。因此,当它超出范围时,在函数执行结束时会被删除。

你的问题“而且,确实”找到“删除”一个“首先,然后返回或先返回,然后删除”一个“?”

a的副本将首先返回,然后a将删除。

如果返回引用,将返回引用,然后将删除对象a。这样您的返回引用无效。

© www.soinside.com 2019 - 2024. All rights reserved.