1

关于 auto_ptr<> 和 auto_ptr_ref<> 的内部实现,我查看了不同的来源。我有这个问题,我不知道为什么。

.... 当从函数返回 'auto_ptr' 时,编译器发现没有合适的 ctor 来复制构造返回的对象。但是有转换为 'auto_ptr_ref' 和 ctor 采用 'auto_ptr_ref' 构造一个 'auto_ptr'。因此,编译器创建一个“auto_ptr_ref”,它基本上只是保存对原始“auto_ptr”的引用,然后从这个对象构造一个“auto_ptr”。就是这样(好吧,当返回一个对象时,编译器通常会经历两次这个过程,因为返回的值被复制到某个地方,但这不会改变这个过程)......(参考http://www.josuttis.com/libbook /auto_ptr.html )

在此示例中,我模拟了 auto_ptr<> 和 auto_ptr_ref<> 的实现,并且能够生成显示编译器确实经历了两次该过程的结果

该示例具有以下基本特征:

1) A 的复制构造函数不采用 const 引用。2) A 具有转换运算符 B 3) A 具有构造函数 A(B);

class B {
};

class A {
public:

A () {
    printf("A default constructor() @ %p\r\n", this);
}

A(B) {
    printf("constructor(B) @ %p\r\n", this);
}
A (A &a) {
    printf("copy constructor(non-const) @ %p\r\n", this);
}

operator B() {
    printf("A convertion constructor(B) @ %p\r\n", this);
    return B();
}
};


A foo()
{
    return A();
}

int main()
{
    A a(foo());
}

所以当A a(foo()))被执行时

1) foo() 生成临时对象 X 2) X 转换为类型 B 3) 构造函数 A(B) 用于构造对象a

这是输出:

A default constructor() @ 0xbfea340f
A convertion constructor(B) @ 0xbfea340f
constructor(B) @ 0xbfea344f
A convertion constructor(B) @ 0xbfea344f
constructor(B) @ 0xbfea344e

我们可以看到编译器两次完成了转换构造步骤 2 和 3。

这是为什么?

4

2 回答 2

1

如果您正在调用返回类类型的函数,则基本上会发生以下情况:

  • 在调用时,调用函数在堆栈上为临时返回值保留一些空间(这必须由调用函数完成,因为被调用函数在堆栈上分配的任何内容都会在函数返回后立即释放)。它将那个空间的地址传递给被调用的函数。

  • 在执行return语句时,被调用函数将返回值从给定return语句的参数构造到调用函数提供的空间中。在您的情况下,该参数是临时A值。

  • 函数返回后,调用者使用被调用函数构造的临时值来执行代码要求的任何操作。在您的情况下,您使用它从它构造一个局部变量。

因此,您A从现有对象构造了一个新类型的对象两次:首先,foo从 return 语句中显式生成的临时对象(整个生命周期在完整表达式的末尾结束,在这种情况下相当于 on return from foo)。其次,afoo.

当然,由于没有适当的复制构造函数可用,在这两种情况下都需要进行B转换。这是有效的,因为return它进行了直接初始化,并且为a您显式编码了这样的直接初始化。

于 2013-07-23T21:15:29.100 回答
0

A被创建了 3 次。一次作为临时,复制两次。其他编译器可能会根据其优化设置返回不同的结果。

return A()创建一个临时A的,然后将其复制到返回A 的第一个副本是您第一次看到步骤 2 和 3。

然后A a(foo());将 return from 复制foo()到 main 中的变量中。再次触发步骤 2 和 3。

于 2013-07-23T20:32:14.790 回答