-1

次の 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 );
}

コピー コンストラクターが正しく動作しない場合、この関数が正しく動作するのはなぜですか?

4

1 に答える 1

3

あなたのコピー コンストラクターは、データ全体を適切にコピーしません。

copy-constructor でコンテンツをコピーせず、メモリを割り当てるだけです。したがって、完全なコピー コンストラクターではありません。この不完全なメソッドは、ムーブ コンストラクターよりも高速である必要があります。

    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 //
            ///////////////////////////////////////////
        }
    }

コピー コンストラクターがメンバーをディープ コピーする必要がない場合、それを移動しても、コピーするよりも多くの利点はありません。

于 2013-11-05T07:56:39.490 に答える