VS 2010,Move构造函数只在move()之后到达并且比复制构造函数慢?

时间:2012-04-16 19:25:46

标签: c++ visual-studio-2010 visual-c++ c++11

尝试测试移动语义我构建了一个分配一些内存的简单类:

class CTest
{
    private:
        std::size_t size;
        char* buffer;

    public:
        CTest(std::size_t size) : size(size), buffer(nullptr)
        {
            buffer = new char[size];
        }

        ~CTest()
        {
            delete[] buffer;
        }

        CTest(const CTest& other) : size(other.size), buffer(nullptr)
        {
            buffer = new char[size];
        }

        CTest(CTest&& other) : size(other.size), buffer(other.buffer)
        {
            other.buffer = nullptr;
        }
};

你可以看到它是一个非常简单的类,当它通过ref复制时,它会分配新的内存(不会复制它的内容,仅用于测试)。 移动构造函数只是使内部指针指向参数数据,没有分配新的内存。

使用带有辅助函数的Windows QueryPerformanceCounter()进行基准测试,如:

template <typename Func>
__int64 Benchmark(Func f, size_t count)
{
    LARGE_INTEGER li = {};
    QueryPerformanceCounter(&li);
    __int64 start = li.QuadPart;

    f(count);

    QueryPerformanceCounter(&li);
    return li.QuadPart - start;
}

非常简单的基准测试功能,保存开始时间并从结束时间中减去它并返回结果。 现在用于测试功能:

void Alloc_Ref(size_t count)
{
    CTest t(1024);
    for(size_t i = 0; i < count; ++i)
        CTest c(t);
}

void Alloc_Move(size_t count)
{
    for(size_t i = 0; i < count; ++i)
        CTest c(CTest(1024));
}

Alloc_Ref使用预先初始化的变量,因此它调用复制构造函数,而Alloc_Move只使用临时类,因此它调用移动构造函数。

我打电话给这样的测试:

cout << "Ref: " << Benchmark(Alloc_Ref, 1000000) << " ms." << endl;
cout << "Move: " << Benchmark(Alloc_Move, 1000000) << " ms." << endl;

问题是,Alloc_Move没有调用移动构造函数,它继续调用复制构造函数,是否有东西丢失?

同样重要的是,当我在Alloc_Move上执行此操作时:CTest c(move(CTest(1024))它会调用移动构造函数但是它比Alloc_Ref速度慢,还有什么东西可以丢失吗?

抱歉这篇长篇文章并提前致谢。

2 个答案:

答案 0 :(得分:3)

  

问题是,Alloc_Move没有调用移动构造函数,它继续调用复制构造函数,是否有东西丢失?

您的分析不正确。如果您使用的是Visual C ++ 2010 SP1编译器,Alloc_Move既不调用复制构造函数也不调用移动构造函数。声明和初始化

CTest c(CTest(1024));

转化为

CTest c(1024);

即,通过调用构造函数c直接初始化CTest(std::size_t size)。没有创建或销毁临时CTest个对象。


在我的Visual Studio 2010 32位虚拟机上,我发现Alloc_MoveAlloc_Ref函数之间的性能差异为20%(后者更快)。我简短地看了一眼生成的组件,但没有看到任何明显的差异原因。使用Visual C ++ 11 Beta编译器(对于x86),Alloc_Move的速度是Alloc_Ref的两倍(我没有进一步调查,我不知道原因是什么)。< / p>

[另请注意,您的测量单位错误:QueryPerformanceCounter不返回毫秒;它会返回滴答声。您需要致电QueryPerformanceFrequency以获取每秒的滴答数,然后相应地划分您的测量值。]

答案 1 :(得分:-2)

为了利用移动语义,您需要显式使用rvalue引用。为了与旧代码兼容,编译器永远不会为您隐式地转换为右值引用;你需要使用std::move或明确施放。

Alloc_Move的可能性较慢,因为您每次构建CTest(1024)时都会构建新的c,而Alloc_Ref仅构建一个CTest(1024) {{1}}并重复使用它。