3

我试图了解这种分配在 c++ 中是如何工作的:

Test other = toto();

这是完整的代码源:

#include <iostream>

class Test
{
public:
    Test()
    {
        j = i++;
        std::cout<<"default constructor "<<j<<std::endl;
    }

    Test(const Test&)
    {
        std::cout<<"constuctor by copy "<<j<<std::endl;
    }
    Test & operator=(const Test&)
    {
        std::cout<<"operator = "<<j<<std::endl;
        return *this;
    }
    int j;
    static int i;
};

int Test::i = 0;

Test toto()
{
    Test t;
    return t;
}

int main()
{
    Test other = toto();
    std::cout<<other.j<<std::endl;
    Test another;
    return 0;
}

代码没有通过复制或运算符 = 使用构造函数,所以我真的不明白它是如何工作的......我使用了 gcc 4.7.0

感谢您的帮助:)

杰罗姆

4

2 回答 2

7

格式语义:

Test other = toto();

涉及多个副本(但没有分配)。但是,允许编译器省略所有不同的实例,这会消除副本;几乎所有的编译器都会做这种优化。

更具体地说,标准没有指定类类型值的返回位置,但通常的解决方案是调用者分配空间,并将指向它的隐藏指针传递给函数。没有上面提到的优化:

Test
toto()
{
    Test t;
    return t;
}

将导致t构造局部变量,然后 return 语句将复制t到隐藏指针指向的空间中。这里的优化(称为命名返回值优化,或 NRVO)导致编译器使用隐藏指针指向的空间 for ,而不是在本地t创建一个单独的。t(显然,当它这样做时,它不会破坏t因为它会在复制之后。)

在声明中:

Test t = toto();

,形式语义将让编译器为 Test 类型的临时分配空间,将此空间的地址作为隐藏指针传递给toto,然后将此临时复制到t并销毁它。这里的优化在于编译器将地址 t直接传递给toto,省略中间临时地址。

于 2012-05-11T12:41:27.160 回答
3

看看返回值优化,这是一种避免构造函数调用的常见优化。

于 2012-05-11T12:35:46.357 回答