当忽略返回值(返回一个对象)时会发生什么?

时间:2013-03-08 16:31:08

标签: c++ return-value copy-constructor

我在Thinking in C ++中经历了这个特殊的例子 - Bruce Eckel。我可以理解语句1(在评论中提到)和语句2 ,但很难理解语句3 当没有返回时,即使函数声明和定义要求返回一个对象用于复制目的。现在实际发生了什么?对于其他两个语句(1和2),我可以推断出编译器阻止了bitcopying,因为我们在类中指定了一个复制构造函数,而是通过我们为在内部传递的对象定义的复制构造函数来处理它。函数以及函数返回的对象。在函数结束之前,函数内的临时对象被复制为返回值,然后被破坏。我是对的吗?

#include <fstream>
#include <string>
using namespace std;
ofstream out("HowMany2.out");
class HowMany2 {
    string name; // Object identifier
    static int objectCount;
    public:
    HowMany2(const string& id = "") : name(id) {
        ++objectCount;
        print("HowMany2()");
    }
    ~HowMany2() {
       --objectCount;
       print("~HowMany2()");
    }
    // The copy-constructor:
    HowMany2(const HowMany2& h) : name(h.name) {
       name += " copy";
       ++objectCount;
       print("HowMany2(const HowMany2&)");
    }
    void print(const string& msg = "") const {
       if(msg.size() != 0)
       out << msg << endl;
       out << '\t' << name << ": "<< "objectCount = "<< objectCount << endl;
    }
};
int HowMany2::objectCount = 0;
// Pass and return BY VALUE:
HowMany2 f(HowMany2 x) {
    x.print("x argument inside f()");
    out << "Returning from f()" << endl;
    return x;
}
int main() {
    HowMany2 h("h");//statement 1 
    out << "Entering f()" << endl;
    HowMany2 h2 = f(h);//statement 2
    h2.print("h2 after call to f()");
    out << "Call f(), no return value" << endl;
    f(h);//statement 3
    out << "After call to f()" << endl;
}

根据Eckel的说法,输出是:

HowMany2()
h: objectCount = 1
Entering f()
HowMany2(const HowMany2&)
h copy: objectCount = 2
x argument inside f()
h copy: objectCount = 2
Returning from f()
HowMany2(const HowMany2&)
h copy copy: objectCount = 3
~HowMany2()
h copy: objectCount = 2
h2 after call to f()
h copy copy: objectCount = 2
Thinking in C++ www.BruceEckel.com
Call f(), no return value
HowMany2(const HowMany2&)
h copy: objectCount = 3
x argument inside f()
h copy: objectCount = 3
Returning from f()
HowMany2(const HowMany2&)
h copy copy: objectCount = 4
~HowMany2()
h copy: objectCount = 3
~HowMany2()
h copy copy: objectCount = 2
After call to f()
~HowMany2()
h copy copy: objectCount = 1
~HowMany2()
h: objectCount = 0

另外,为什么我们不能为返回值分配额外的存储空间,以便我们可以在函数调用之前将它们存储在那里。它可以替代使用引用吗? 提前谢谢!!!

2 个答案:

答案 0 :(得分:2)

没有复制构造函数调用,因为忽略了函数的返回值 请注意,即使可能需要副本,大多数编译器也可以在某些情况下通过 copy elision 来避免复制构造函数调用。

由于x是函数的本地对象(有值传递),因此一旦函数范围x结束,{ }就会被销毁。< / p>

答案 1 :(得分:2)

  

对于其他两个语句(1和2),我可以推断出编译器会阻止bitcopying,因为我们在类中指定了一个复制构造函数,而是通过我们为在内部传递的对象定义的复制构造函数来处理它。函数以及函数返回的对象。在函数结束之前,函数内的临时对象被复制为返回值然后被破坏。我是对的吗?

在C ++中:

  1. 临时是从返回的对象 move-construct (如果你没有定义一个move-constructor,这将是一个copy-construction);那么,
  2. 分配返回值的对象是其中之一 移动分配(如果您使用t = f())或移动构造(如果您 从返回值中使用T t = f())(如果没有定义移动赋值运算符,则移动赋值变为复制赋值,如果没有定义移动构造函数,则移动构造变为复制构造);那么,
  3. 临时被毁坏。
  4.   即使函数声明和定义要求为复制目的返回一个对象,

    在没有返回时很难理解语句3

    如果您只是不使用返回的值,则编译器没有理由调用任何复制构造函数。从函数返回时,返回的对象将超出范围,这就是一切。

    如果你在这里看到对copy-construction的调用,那可能是因为编译器无法优化上面的步骤2和3(编译器允许,但不是< em>必需,以免接听电话。)