Visual C 上的复制省略2010 测试版 2

发布于 2024-08-10 13:36:28 字数 4963 浏览 2 评论 0原文

我正在阅读想要速度吗?在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: No

Move 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: Yes

Move 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: Yes

Move 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夏了南城 2024-08-17 13:36:28

感谢您回复戴夫。

我已将测试添加到该示例中:
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

女中豪杰 2024-08-17 13:36:28

唔。

看来,如果您更改数据构造函数

MoveableClass::MoveableClass(std::vector<double> data)

以通过引用接受向量,就像这样,

MoveableClass::MoveableClass(const std::vector<double>& data) 

它就可以正常工作!如果按值传递向量,为什么不起作用?

如果有人想在那里运行测试,这里还有一个应该在早期版本的 MSVC 上编译的版本。它不包含 C++0x 功能: http://pastebin.com/f3bcb6ed1

Hmm.

It seems that if you change the data constructor

MoveableClass::MoveableClass(std::vector<double> data)

to accept the vector by reference, like so,

MoveableClass::MoveableClass(const std::vector<double>& data) 

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

月竹挽风 2024-08-17 13:36:28

也许更新和维护 这个示例是个好主意 来自 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文