为什么不更快地移动构造函数?
Why isn't move constructor faster?
我有一个非常简单的测试用例,其中一个 Geometry class 包含一个非常大的 std::vector。我正在比较 copy/move 构造函数的速度:
class Geometry
{
public:
Geometry(size_t size) : m_data(size) {}
Geometry(const Geometry& other) : m_data(other.m_data)
{ std::cout << "Copy constructor" << std::endl; }
Geometry(Geometry&& other) noexcept : m_data(std::move(other.m_data))
{ std::cout << "Move constructor" << std::endl; }
private:
std::vector<double> m_data;
};
int main()
{
Geometry geometry(1000000000);
{
ScopedTimer scopedTimer("copy constructor");
Geometry geometry2(geometry);
}
{
ScopedTimer scopedTimer("move constructor");
Geometry geometry2(std::move(geometry));
}
}
我原以为复制构造函数会非常慢,而移动构造函数几乎是瞬时的,因为它只需要将句柄交换到底层向量资源。然而,这不是我在这里观察到的(ScopedTimer 只是一个基于 std::chrono 的简单计时器,returns 其构建和销毁之间的持续时间)。这是我在发布配置中得到的输出(在调试配置中观察到类似的趋势):
Copy constructor
6832 ms copy constructor
Move constructor
2605 ms move constructor
移动构造函数大约快三倍,更好,但不是我所期望的。为什么不比这更快?我期望移动构造函数是 O(1)。为什么使用更大的向量需要更长的时间?代码不需要分配任何东西等等。我错过了什么吗?
您正在测量矢量破坏时间。没有它,移动构造函数即使在调试模式下也不会花时间:
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include <chrono>
class ScopedTimer
{
std::string m_text;
::std::chrono::high_resolution_clock::time_point start;
public: ScopedTimer(::std::string const & text):
m_text{text}, start{::std::chrono::high_resolution_clock::now()} {}
public: void Report(void)
{
auto const end{::std::chrono::high_resolution_clock::now()};
::std::cout << m_text << " " << ::std::chrono::duration_cast<::std::chrono::milliseconds>(end - start).count() << ::std::endl;
}
};
class Geometry
{
public:
Geometry(size_t size) : m_data(size) {}
Geometry(const Geometry& other) : m_data(other.m_data)
{ std::cout << "Copy constructor" << std::endl; }
Geometry(Geometry&& other) noexcept : m_data(std::move(other.m_data))
{ std::cout << "Move constructor" << std::endl; }
private:
std::vector<double> m_data;
};
int main()
{
Geometry geometry(1000000000);
{
ScopedTimer scopedTimer("copy constructor");
{
Geometry geometry2(geometry);
scopedTimer.Report();
}
scopedTimer.Report();
}
{
ScopedTimer scopedTimer("move constructor");
{
Geometry geometry2(std::move(geometry));
scopedTimer.Report();
}
scopedTimer.Report();
}
return 0;
}
Copy constructor
copy constructor 5099
copy constructor 6526
Move constructor
move constructor 0
move constructor 1319
我有一个非常简单的测试用例,其中一个 Geometry class 包含一个非常大的 std::vector。我正在比较 copy/move 构造函数的速度:
class Geometry
{
public:
Geometry(size_t size) : m_data(size) {}
Geometry(const Geometry& other) : m_data(other.m_data)
{ std::cout << "Copy constructor" << std::endl; }
Geometry(Geometry&& other) noexcept : m_data(std::move(other.m_data))
{ std::cout << "Move constructor" << std::endl; }
private:
std::vector<double> m_data;
};
int main()
{
Geometry geometry(1000000000);
{
ScopedTimer scopedTimer("copy constructor");
Geometry geometry2(geometry);
}
{
ScopedTimer scopedTimer("move constructor");
Geometry geometry2(std::move(geometry));
}
}
我原以为复制构造函数会非常慢,而移动构造函数几乎是瞬时的,因为它只需要将句柄交换到底层向量资源。然而,这不是我在这里观察到的(ScopedTimer 只是一个基于 std::chrono 的简单计时器,returns 其构建和销毁之间的持续时间)。这是我在发布配置中得到的输出(在调试配置中观察到类似的趋势):
Copy constructor
6832 ms copy constructor
Move constructor
2605 ms move constructor
移动构造函数大约快三倍,更好,但不是我所期望的。为什么不比这更快?我期望移动构造函数是 O(1)。为什么使用更大的向量需要更长的时间?代码不需要分配任何东西等等。我错过了什么吗?
您正在测量矢量破坏时间。没有它,移动构造函数即使在调试模式下也不会花时间:
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include <chrono>
class ScopedTimer
{
std::string m_text;
::std::chrono::high_resolution_clock::time_point start;
public: ScopedTimer(::std::string const & text):
m_text{text}, start{::std::chrono::high_resolution_clock::now()} {}
public: void Report(void)
{
auto const end{::std::chrono::high_resolution_clock::now()};
::std::cout << m_text << " " << ::std::chrono::duration_cast<::std::chrono::milliseconds>(end - start).count() << ::std::endl;
}
};
class Geometry
{
public:
Geometry(size_t size) : m_data(size) {}
Geometry(const Geometry& other) : m_data(other.m_data)
{ std::cout << "Copy constructor" << std::endl; }
Geometry(Geometry&& other) noexcept : m_data(std::move(other.m_data))
{ std::cout << "Move constructor" << std::endl; }
private:
std::vector<double> m_data;
};
int main()
{
Geometry geometry(1000000000);
{
ScopedTimer scopedTimer("copy constructor");
{
Geometry geometry2(geometry);
scopedTimer.Report();
}
scopedTimer.Report();
}
{
ScopedTimer scopedTimer("move constructor");
{
Geometry geometry2(std::move(geometry));
scopedTimer.Report();
}
scopedTimer.Report();
}
return 0;
}
Copy constructor
copy constructor 5099
copy constructor 6526
Move constructor
move constructor 0
move constructor 1319