表达式 MyClass a = b + c 是复制初始化吗?
Is the expression MyClass a = b + c a copy initialization?
我知道像 MyClass a = b 这样的表达式是一个复制初始化,它会调用复制构造函数。
MyClass a = b + c 呢?
我试过了。在visual studio 2015 中,表达式似乎不是复制初始化也不是复制assignment.So 是什么?
下面是我测试的代码:
class MyClass
{
public:
MyClass()
{
cout << "default constructor has been called!" << endl;
}
MyClass(const MyClass& cls)
{
cout << "copy constructor has been called!" << endl;
}
MyClass operator+(const MyClass& cls) const
{
cout << "operator + has been called!" << endl;
return MyClass();
}
MyClass& operator=(const MyClass& cls)
{
cout << "operator = has been called!" << endl;
return *this;
}
};
int main()
{
MyClass b, c;
MyClass a = b + c;
return 0;
}
输出为
default constructor has been called!
default constructor has been called!
operator + has been called!
default constructor has been called!
这种情况下的复制构造函数may be elided。
从c++类型的角度来看,
没有区别
MyClass a = b + c;
和
MyClass a = MyClass();
因为 operator+
returns 右值 MyClass。由于您刚刚创建了您希望 a
成为的对象,它只是将该对象直接变成 a
。
这在此处的第一个示例中进行了描述:http://en.cppreference.com/w/cpp/language/copy_elision
你所体验的叫做return价值优化(参见What are copy elision and return value optimization?)。
编译器优化代码(以最小化创建的对象)并使 a
实际上是声明的本地对象,并由您的 +
运算符 return 编辑。然后,没有使用复制构造函数。这就是您在这里观察到的。
为了很好地观察这一点,更改代码以查看对象内存地址:
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{
cout << "default constructor has been called for " << std::hex << this << endl;
}
MyClass(const MyClass& cls)
{
cout << "copy constructor has been called for " << std::hex << this << " (copied from " << &cls << ")" << endl;
}
MyClass operator+(const MyClass& cls) const
{
cout << "operator + has been called!" << endl;
MyClass res;
cout << "operator + returns temporary object " << std::hex << &res << endl;
return res;
}
MyClass& operator=(const MyClass& cls)
{
cout << "operator = has been called!" << endl;
return *this;
}
};
int main()
{
MyClass b, c;
MyClass a = b + c;
cout << "a object is " << std::hex << &a << endl;
return 0;
}
它输出:
default constructor has been called for 0x7ffd44b769fd
default constructor has been called for 0x7ffd44b769fe
operator + has been called!
default constructor has been called for 0x7ffd44b769ff
operator + returns temporary object 0x7ffd44b769ff
a object is 0x7ffd44b769ff
由于编译器优化,您看到在 operator+
中创建的临时对象与 a
(0x7ffd44b769ff
) 相同。
如果您使用 g++,请使用 -fno-elide-constructors
进行编译以禁用此编译器优化。现在的输出是:
default constructor has been called for 0x7ffd92847d1c
default constructor has been called for 0x7ffd92847d1d
operator + has been called!
default constructor has been called for 0x7ffd92847cff
operator + returns temporary object 0x7ffd92847cff
copy constructor has been called for 0x7ffd92847d1f (copied from 0x7ffd92847cff)
copy constructor has been called for 0x7ffd92847d1e (copied from 0x7ffd92847d1f)
a object is 0x7ffd92847d1e
你看到现在 operator+
创建了一个本地对象 (0x7ffd92847cff
),稍后将其复制为 return 语句的临时对象(将 0x7ffd92847cff
复制到 0x7ffd92847d1f
), 最后用来构造一个by copy(copying 0x7ffd92847d1f
to 0x7ffd92847d1e
).
我知道像 MyClass a = b 这样的表达式是一个复制初始化,它会调用复制构造函数。
MyClass a = b + c 呢?
我试过了。在visual studio 2015 中,表达式似乎不是复制初始化也不是复制assignment.So 是什么?
下面是我测试的代码:
class MyClass
{
public:
MyClass()
{
cout << "default constructor has been called!" << endl;
}
MyClass(const MyClass& cls)
{
cout << "copy constructor has been called!" << endl;
}
MyClass operator+(const MyClass& cls) const
{
cout << "operator + has been called!" << endl;
return MyClass();
}
MyClass& operator=(const MyClass& cls)
{
cout << "operator = has been called!" << endl;
return *this;
}
};
int main()
{
MyClass b, c;
MyClass a = b + c;
return 0;
}
输出为
default constructor has been called!
default constructor has been called!
operator + has been called!
default constructor has been called!
这种情况下的复制构造函数may be elided。
从c++类型的角度来看,
没有区别MyClass a = b + c;
和
MyClass a = MyClass();
因为 operator+
returns 右值 MyClass。由于您刚刚创建了您希望 a
成为的对象,它只是将该对象直接变成 a
。
这在此处的第一个示例中进行了描述:http://en.cppreference.com/w/cpp/language/copy_elision
你所体验的叫做return价值优化(参见What are copy elision and return value optimization?)。
编译器优化代码(以最小化创建的对象)并使 a
实际上是声明的本地对象,并由您的 +
运算符 return 编辑。然后,没有使用复制构造函数。这就是您在这里观察到的。
为了很好地观察这一点,更改代码以查看对象内存地址:
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{
cout << "default constructor has been called for " << std::hex << this << endl;
}
MyClass(const MyClass& cls)
{
cout << "copy constructor has been called for " << std::hex << this << " (copied from " << &cls << ")" << endl;
}
MyClass operator+(const MyClass& cls) const
{
cout << "operator + has been called!" << endl;
MyClass res;
cout << "operator + returns temporary object " << std::hex << &res << endl;
return res;
}
MyClass& operator=(const MyClass& cls)
{
cout << "operator = has been called!" << endl;
return *this;
}
};
int main()
{
MyClass b, c;
MyClass a = b + c;
cout << "a object is " << std::hex << &a << endl;
return 0;
}
它输出:
default constructor has been called for 0x7ffd44b769fd
default constructor has been called for 0x7ffd44b769fe
operator + has been called!
default constructor has been called for 0x7ffd44b769ff
operator + returns temporary object 0x7ffd44b769ff
a object is 0x7ffd44b769ff
由于编译器优化,您看到在 operator+
中创建的临时对象与 a
(0x7ffd44b769ff
) 相同。
如果您使用 g++,请使用 -fno-elide-constructors
进行编译以禁用此编译器优化。现在的输出是:
default constructor has been called for 0x7ffd92847d1c
default constructor has been called for 0x7ffd92847d1d
operator + has been called!
default constructor has been called for 0x7ffd92847cff
operator + returns temporary object 0x7ffd92847cff
copy constructor has been called for 0x7ffd92847d1f (copied from 0x7ffd92847cff)
copy constructor has been called for 0x7ffd92847d1e (copied from 0x7ffd92847d1f)
a object is 0x7ffd92847d1e
你看到现在 operator+
创建了一个本地对象 (0x7ffd92847cff
),稍后将其复制为 return 语句的临时对象(将 0x7ffd92847cff
复制到 0x7ffd92847d1f
), 最后用来构造一个by copy(copying 0x7ffd92847d1f
to 0x7ffd92847d1e
).