Visual C 上的复制省略2010 测试版 2
我正在阅读想要速度吗?在C++ Next 博客上传递值并创建这个程序来感受 C++0x 中的复制省略和移动语义:
#include <vector>
#include <iostream>
class MoveableClass {
public:
MoveableClass() : m_simpleData(0), instance(++Instances) {
std::cout << "Construct instance " << instance << " (no data)" << std::endl;
}
MoveableClass(std::vector<double> data) : m_data(std::move(data)), m_simpleData(0), instance(++Instances) {
std::cout << "Construct instance " << instance << " (with data)" << std::endl;
}
MoveableClass(int simpleData) : m_simpleData(simpleData), instance(++Instances) {
std::cout << "Construct instance " << instance << " (with simple data)" << std::endl;
}
MoveableClass(const MoveableClass& other)
: m_data(other.m_data), m_simpleData(other.m_simpleData), instance(++Instances)
{
std::cout << "Construct instance " << instance << " from a copy of " << other.instance << std::endl;
Elided = false;
}
MoveableClass(MoveableClass&& other)
: m_data(std::move(other.m_data)), m_simpleData(other.m_simpleData), instance(++Instances)
{
std::cout << "Construct instance " << instance << " from a move of " << other.instance << std::endl;
Elided = false;
}
MoveableClass& operator=(MoveableClass other) {
std::cout << "Assign to instance " << instance << " from " << other.instance << std::endl;
other.Swap(*this);
return *this;
}
~MoveableClass() {
std::cout << "Destroy instance " << instance << std::endl;
--Instances;
}
void Swap(MoveableClass& other) {
std::swap(m_data, other.m_data);
std::swap(m_simpleData, other.m_simpleData);
}
static int Instances;
static bool Elided;
private:
int instance;
int m_simpleData;
std::vector<double> m_data;
};
int MoveableClass::Instances = 0;
bool MoveableClass::Elided = true;
std::vector<double> BunchOfData() {
return std::vector<double>(9999999);
}
int SimpleData() {
return 9999999;
}
MoveableClass CreateRVO() {
return MoveableClass(BunchOfData());
}
MoveableClass CreateNRVO() {
MoveableClass named(BunchOfData());
return named;
}
MoveableClass CreateRVO_Simple() {
return MoveableClass(SimpleData());
}
MoveableClass CreateNRVO_Simple() {
MoveableClass named(SimpleData());
return named;
}
int main(int argc, char* argv[]) {
std::cout << "\nMove assign from RVO: " << '\n';
{
MoveableClass a;
a = CreateRVO();
}
std::cout << "Move elided: " << (MoveableClass::Elided ? "Yes" : "No") << '\n';
MoveableClass::Elided = true; // reset for next test
std::cout << "\nMove assign from RVO simple: " << '\n';
{
MoveableClass a;
a = CreateRVO_Simple();
}
std::cout << "Move elided: " << (MoveableClass::Elided ? "Yes" : "No") << '\n';
MoveableClass::Elided = true; // reset for next test
std::cout << "\nMove assign from NRVO: " << '\n';
{
MoveableClass a;
a = CreateNRVO();
}
std::cout << "Move elided: " << (MoveableClass::Elided ? "Yes" : "No") << '\n';
MoveableClass::Elided = true; // reset for next test
std::cout << "\nMove assign from NRVO simple: " << std::endl;
{
MoveableClass a;
a = CreateNRVO_Simple();
}
std::cout << "Move elided: " << (MoveableClass::Elided ? "Yes" : "No") << '\n';
MoveableClass::Elided = true; // reset for next test
}
这是我在发布模式下编译时得到的输出Visual C++ 10.0(测试版 2):
从 RVO 移动分配:
构造实例1(无数据)
构造实例2(带数据)
从 2 的移动构造实例 3
销毁实例 2
从 3 分配给实例 1
销毁实例 3
销毁实例 1
移动已删除:否从 RVO 简单地移动分配:
构造实例1(无数据)
构造实例2(使用简单数据)
从 2 分配给实例 1
销毁实例 2
销毁实例 1
移动已删除:是从 NRVO 移动分配:
构造实例1(无数据)
构造实例2(带数据)
从 2 分配给实例 1
销毁实例 2
销毁实例 1
移动已删除:是从 NRVO 简单地移动分配:
构造实例1(无数据)
构造实例2(使用简单数据)
从 2 分配给实例 1
销毁实例 2
销毁实例 1
删除移动:是
但是,我对一件事感到困惑。正如您所看到的,除了第一个动作之外,所有动作都被忽略了。为什么编译器不能在第 86 行使用 MoveableClass(std::vector) 执行 RVO,但可以在第 97 行使用 MoveableClass(int) 执行 RVO?这只是 MSVC 的一个错误还是有充分的理由?如果有充分的理由,为什么它仍然可以在第 91 行对 MoveableClass(std::vector) 执行 NRVO?
我想了解它,这样我就可以快乐地睡觉了。 :)
I was reading Want Speed? Pass by Value on the C++ Next blog and created this program to get a feel for copy elision and move semantics in C++0x:
#include <vector>
#include <iostream>
class MoveableClass {
public:
MoveableClass() : m_simpleData(0), instance(++Instances) {
std::cout << "Construct instance " << instance << " (no data)" << std::endl;
}
MoveableClass(std::vector<double> data) : m_data(std::move(data)), m_simpleData(0), instance(++Instances) {
std::cout << "Construct instance " << instance << " (with data)" << std::endl;
}
MoveableClass(int simpleData) : m_simpleData(simpleData), instance(++Instances) {
std::cout << "Construct instance " << instance << " (with simple data)" << std::endl;
}
MoveableClass(const MoveableClass& other)
: m_data(other.m_data), m_simpleData(other.m_simpleData), instance(++Instances)
{
std::cout << "Construct instance " << instance << " from a copy of " << other.instance << std::endl;
Elided = false;
}
MoveableClass(MoveableClass&& other)
: m_data(std::move(other.m_data)), m_simpleData(other.m_simpleData), instance(++Instances)
{
std::cout << "Construct instance " << instance << " from a move of " << other.instance << std::endl;
Elided = false;
}
MoveableClass& operator=(MoveableClass other) {
std::cout << "Assign to instance " << instance << " from " << other.instance << std::endl;
other.Swap(*this);
return *this;
}
~MoveableClass() {
std::cout << "Destroy instance " << instance << std::endl;
--Instances;
}
void Swap(MoveableClass& other) {
std::swap(m_data, other.m_data);
std::swap(m_simpleData, other.m_simpleData);
}
static int Instances;
static bool Elided;
private:
int instance;
int m_simpleData;
std::vector<double> m_data;
};
int MoveableClass::Instances = 0;
bool MoveableClass::Elided = true;
std::vector<double> BunchOfData() {
return std::vector<double>(9999999);
}
int SimpleData() {
return 9999999;
}
MoveableClass CreateRVO() {
return MoveableClass(BunchOfData());
}
MoveableClass CreateNRVO() {
MoveableClass named(BunchOfData());
return named;
}
MoveableClass CreateRVO_Simple() {
return MoveableClass(SimpleData());
}
MoveableClass CreateNRVO_Simple() {
MoveableClass named(SimpleData());
return named;
}
int main(int argc, char* argv[]) {
std::cout << "\nMove assign from RVO: " << '\n';
{
MoveableClass a;
a = CreateRVO();
}
std::cout << "Move elided: " << (MoveableClass::Elided ? "Yes" : "No") << '\n';
MoveableClass::Elided = true; // reset for next test
std::cout << "\nMove assign from RVO simple: " << '\n';
{
MoveableClass a;
a = CreateRVO_Simple();
}
std::cout << "Move elided: " << (MoveableClass::Elided ? "Yes" : "No") << '\n';
MoveableClass::Elided = true; // reset for next test
std::cout << "\nMove assign from NRVO: " << '\n';
{
MoveableClass a;
a = CreateNRVO();
}
std::cout << "Move elided: " << (MoveableClass::Elided ? "Yes" : "No") << '\n';
MoveableClass::Elided = true; // reset for next test
std::cout << "\nMove assign from NRVO simple: " << std::endl;
{
MoveableClass a;
a = CreateNRVO_Simple();
}
std::cout << "Move elided: " << (MoveableClass::Elided ? "Yes" : "No") << '\n';
MoveableClass::Elided = true; // reset for next test
}
Here is the output I get when compiled in release mode on Visual C++ 10.0 (Beta 2):
Move assign from RVO:
Construct instance 1 (no data)
Construct instance 2 (with data)
Construct instance 3 from a move of 2
Destroy instance 2
Assign to instance 1 from 3
Destroy instance 3
Destroy instance 1
Move elided: NoMove assign from RVO simple:
Construct instance 1 (no data)
Construct instance 2 (with simple data)
Assign to instance 1 from 2
Destroy instance 2
Destroy instance 1
Move elided: YesMove assign from NRVO:
Construct instance 1 (no data)
Construct instance 2 (with data)
Assign to instance 1 from 2
Destroy instance 2
Destroy instance 1
Move elided: YesMove assign from NRVO simple:
Construct instance 1 (no data)
Construct instance 2 (with simple data)
Assign to instance 1 from 2
Destroy instance 2
Destroy instance 1
Move elided: Yes
However, I am perplexed by one thing. As you can see, all of the moves are elided except for the first one. Why can't the compiler perform RVO with a MoveableClass(std::vector) at line 86, but can with a MoveableClass(int) at line 97? Is this just a bug with MSVC or is there a good reason for this? And if there is a good reason, why can it still perform NRVO on a MoveableClass(std::vector) at line 91?
I'd like to understand it so I can go to sleep happy. :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
感谢您回复戴夫。
我已将测试添加到该示例中:
pastebin.com/f7c8ca0d6
奇怪的是,它表明除了 NRVO 之外,所有类型的省略都没有被执行!
编辑:实际上我想这是因为这是对象有名称的唯一测试。
我还尝试了其他STL类型并得到了相同的结果。然而,当尝试我自己的非 Pod 类型时,它会按预期工作。我想不出 STL 类型有什么特别之处可能会导致这种情况,所以我不知道还能尝试什么。
我将提交错误报告。
编辑:在此处提交
谢谢
Thanks for replying Dave.
I've added my tests to that example:
pastebin.com/f7c8ca0d6
Curiously it shows that all types of elisions are not being performed except for NRVO!
Edit: Actually I suppose this is because it is the only test where the object ever has a name.
I also tried other STL types and got the same result. However when trying my own non-pod types it works as expected. I can't think what's special about the STL types that could be causing this so I don't know what else to try.
I'll submit a bug report.
Edit: Submitted here
Thanks
唔。
看来,如果您更改数据构造函数
以通过引用接受向量,就像这样,
它就可以正常工作!如果按值传递向量,为什么不起作用?
如果有人想在那里运行测试,这里还有一个应该在早期版本的 MSVC 上编译的版本。它不包含 C++0x 功能: http://pastebin.com/f3bcb6ed1
Hmm.
It seems that if you change the data constructor
to accept the vector by reference, like so,
it works fine! Why does it not work if you pass the vector by value?
Also here's a version that should compile on earlier versions of MSVC, if anybody wants to run the test there. It contains no C++0x features: http://pastebin.com/f3bcb6ed1
也许更新和维护 这个示例是个好主意 来自 cpp-next ,您的测试版本失败,因此可以有一个全面的,规范测试。
Maybe it'd be a good idea to update and maintain this example from cpp-next with a version of your test that fails, so there can be one comprehensive, canonical test.