在return语句中调用构造函数

时间:2012-06-08 00:35:57

标签: c++ visual-c++

class test{

public:

    int data;
    test(const test& ){cout<<"INSIDE COPY CON "<<endl;}
    test(int val = 0) : data(val){ cout<<"INSIDE CON "<<endl; }

    test testfun(const test& obj)
    {
        cout<<"data : "<<data<<endl;
        //test test3(this->data + obj.data);
        //cout<<"test3 :"<<test3.data<<endl;
        //return test3;   //This will work only if return type is changed to const ref
        return test(data + obj.data); 


    }
};

int main()
{

    test testO1(1);
    test testO2(2);
    test testO3 = testO1.testfun(testO2);

    cout<<testO3.data<<endl;


    getchar();


}

输出:

INSIDE CON

INSIDE CON

data : 1

INSIDE CON

3

在return语句中调用构造函数时会发生什么?因为我能够按价值返回并且它起作用我认为它不是临时位置。或者它是将对象创建为临时对象并使用复制构造函数来复制值,这就是为什么复制构造函数中的打印没有被打印的情况。

3 个答案:

答案 0 :(得分:10)

它创建一个临时对象,然后将其复制到返回值。

但是为了提高效率,C ++允许对复制构造函数(或C ++ 11中的移动构造函数)的调用 elided ,因此您不应该依赖于复制构造函数的副作用。

请参阅Return Value OptimizationWant Speed? Pass By Value

答案 1 :(得分:4)

你提出了一个深刻的问题。

由编译器和相关工具链决定要做什么,但基本模式如下。在调用testfun()之前,调用者[main()(在您的示例中)为堆栈上的test03保留空间。然后,它会将test03的地址传递给testfun()

函数testfun()必须以某种方式将test对象放在调用者提供的地址处。如果函数只有一个return语句,可以使用调用者提供的存储来构建返回值。它不需要使用自己的存储。它可以使用main()

现在,这种策略并不总是有效。当像testfun()这样的函数有两个不同的return语句时,它通常会失败,其中一个或两个返回语句不是临时对象而是返回命名对象。在这种情况下,编译器被迫执行否则不必要的复制返回。但是,更常见的情况类似于你的情况,其中testfun()只是直接在main()想要它的地方建立返回值。在这种情况下,不会发生实际复制。

因此,在这样的情况下,由编译器决定是否在返回时调用复制构造函数。

答案 2 :(得分:0)

我告诉你return一个构造函数时发生了什么,让我们为你做一个很好的例子。我引用了一个名为Counter的类,它以两种方式返回:

按临时对象返回:

// method 1
class Counter
{
private :
    int count;
public :
    Counter() : count(0) {}
    int get_count(void);
    Counter operator++(int);
};

int Counter::get_count()
{
    return count;
}

Counter Counter::operator++(int)
{
    count++;
    // create a temp object and assigning count value, then return.
    Counter temp;
    temp.count = count;
    return temp;
}

通过无名临时对象返回:

// method 2
class Counter
{
private :
    int count;
public :
    Counter() : count(0) {}
    Counter(int c) : count(c) {}
    int get_count(void);
    Counter operator++(int);
};

int Counter::get_count()
{
    return count;
}

Counter Counter::operator++(int)
{
    count++;
    // call 'Counter(int c)' constructor
    return Counter(count);
}

主要:

#include <iostream>
using namespace std;

int main()
{
    Counter c1, c2;
    c1++;
    c1++;
    c2 = c1++;
    cout << "c1=" << c1.get_count() << endl;
    cout << "c2=" << c2.get_count() << endl;
    return 0;
}

两种方法的输出相同,第二return Counter(count);中的class语句执行第一个中所有三个语句所做的操作。这个语句创建了一个Counter类型的对象,这个对象没有名字;它不会长到足以需要一个。这个未命名的对象初始化为参数count提供的值,一旦未命名的对象初始化为count的值,就可以返回它。

第一个class的效果与第二个class的效果相同:

输出:

c1= 3
c2= 3

通知,在c2 = c1++;声明中c1增加,然后分配到c2