C++11 移动构造函数的速度比 C++98 复制构造函数慢
C++11 move constructor slower than C++98 copy constructor
让我们看看以下三个类:
class IntTab0 {
private:
int length;
int* data;
public:
IntTab0(): length(0), data(nullptr) {}
IntTab0(int size): length(size) {
assert(size > 0);
data = new int[length];
}
IntTab0(const IntTab0& rhs): length(0), data(nullptr) {
if (rhs.data) {
length = rhs.length;
data = new int(*rhs.data);
}
}
~IntTab0() {
delete[] data;
}
void swap(IntTab0& second) {
using std::swap;
swap(length, second.length);
swap(data, second.data);
}
};
class IntTab1 : public IntTab0 {
public:
IntTab1(): IntTab0() {}
IntTab1(int size): IntTab0(size) {}
IntTab1(const IntTab1& rhs): IntTab0(rhs) {}
IntTab1(IntTab1&& rhs) noexcept {
swap(rhs);
}
IntTab1& operator=(IntTab1&& rhs) noexcept {
swap(rhs);
return *this;
}
};
class IntTab2 : public IntTab0 {
public:
IntTab2(): IntTab0() {}
IntTab2(int size) : IntTab0(size) {}
IntTab2(const IntTab2& rhs): IntTab0(rhs) {}
IntTab2(IntTab2&& rhs) {
swap(rhs);
}
IntTab2& operator=(IntTab2&& rhs) {
swap(rhs);
return *this;
}
};
我还有一个函数来衡量它们中的每一个的性能:
template<class Value>
void test_Performance() {
std::vector <Value> vit;
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
for (int i = 0; i < 100000; i++) {
Value it(5);
vit.push_back(it);
}
std::vector <Value> vitCopy(std::move(vit));
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::cout << "elapsed time for IntTab" << it++ << ": " << elapsed_seconds.count() << "sn";
}
我不太明白的是针对我的类的每个实例运行此性能测试的结果。我怀疑 IntTab1 应该是最快的一个,因为它使用 move 构造函数和 noexexcept 的移动赋值运算符。事实上,在我的环境中,结果是相反的 - 最快的是仅使用复制构造函数和赋值运算符的 C++98 版本。以下是我的结果:
IntTab 的运行时间:2.2873e-05s
IntTab1 的运行时间:2.4139e-05s
IntTab2 的运行时间:2.3554e-05s
有人能解释这种奇怪的行为吗?
编辑
根据关于错误的复制构造函数(不做真正的深度复制)的评论 - 我有一个测试函数,我假设它测试了这种行为:
void test_IntTab( void ) {
IntTab0 it( 5 );
it[0] = 10;
it[4] = 20;
assert( it.size() == 5 );
assert( it[0] == 10 );
assert( it[4] == 20 );
IntTab0 iu( 10 );
iu[0] = 17;
iu[4] = 34;
assert( iu.size() == 10 );
assert( iu[0] == 17 );
assert( iu[4] == 34 );
iu.swap( it );
assert( iu.size() == 5 );
assert( iu[0] == 10 );
assert( it.size() == 10 );
assert( it[0] == 17 );
IntTab0 is( iu );
assert( is.size() == 5 );
assert( is[0] == 10 );
IntTab0 iw;
iw = it;
assert( iw.size() == 10 );
assert( iw[0] == 17 );
it[0] = 1;
iu[0] = 2;
is[0] = 3;
iw[0] = 4;
assert( it[0] == 1 );
assert( iu[0] == 2 );
assert( is[0] == 3 );
assert( iw[0] == 4 );
}
如果我的复制构造函数无法正常工作,为什么此函数可以正常运行?
复制构造函数没有正确复制整个数据。
您不会复制复制构造函数中的内容,它只是分配内存。所以,它不是完整的复制构造函数。这个不完整的方法应该比移动构造函数更快。
IntTab0(const IntTab0& rhs): length(0), data(nullptr) {
if (rhs.data) {
length = rhs.length;
data = new int(*rhs.data);
///////////////////////////////////////////
// Assuming data is an array //
// std::copy from rhs.data to this->data //
///////////////////////////////////////////
}
}
如果您的复制构造函数不必深度复制成员,那么移动它比复制没有太多优势。
相关文章:
- "error: no matching function for call to"构造函数错误
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 选择要调用的构造函数
- 如何委托派生类使用其父构造函数?
- 构造函数正在调用一个使用当前类类型的函数
- 没有用于初始化C++中的变量模板的匹配构造函数
- 初始化具有非默认构造函数的std::数组项的更好方法
- 当从函数参数中的临时值调用复制构造函数时
- 在c++构造函数中使用随机字符串生成器
- 一对向量构造函数:初始值设定项列表与显式构造
- 我正在使用dev c ++,但收到错误(C++98'array'必须由构造函数初始化)
- 在 C++98 中,'dvd1' 必须由构造函数初始化,而不是由 '{...}' 初始化
- 移动返回对象的构造函数会中断C++98 代码?
- C++11 移动构造函数的速度比 C++98 复制构造函数慢
- 在 C++98 中实现移动构造函数和移动赋值运算符以获得更好的性能
- 我们需要一个可访问的复制构造函数来初始化C++98/03中的值吗
- 具有多个构造函数的c++ (c++ 98)函子