次の 3 つのクラスを見てみましょう。
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() << "s\n";
}
私がよく理解していないのは、クラスの各インスタンスに対してこのパフォーマンス テストを実行した結果です。IntTab1 は移動コンストラクターと移動代入演算子を noexcept で使用するため、最も高速であると思われます。実際、私の環境では結果は反対です。最速のものは、コピー コンストラクターと代入演算子のみを使用する 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 );
}
コピー コンストラクターが正しく動作しない場合、この関数が正しく動作するのはなぜですか?