テンプレートデータでstd :: move()を安全に使用する方法

meissnersd

私はVS2013とC ++ 11で作業しています。

カスタムのテンプレート化されたコレクションを実装しています。コレクションが容量を超えると、ストレージのサイズが変更されます。その時点で、データは古いストレージから新しいストレージに移動する必要があります。

データ要素Tに安全な移動セマンティクスを適用したいと思います。データ要素がリソースを所有している場合、リソースの所有権は元のストレージから盗まれ、新しいストレージに移動する必要があります。典型的なケースは、データ配列または他のリソースへの文字列またはポインタです。

明示的な移動コンストラクターと移動代入演算子を持ついくつかのデータ型があります。しかし、明示的な移動コンストラクター(DeepData1)を持つタイプ自体が、些細なコンストラクター(DeepData2)を持つ他のデータ構造体のメンバーである場合、バグが発生します。この記事の読み方によると、DeepData2で暗黙的なコンパイラー生成のmoveコンストラクターを取得する必要があると思います。http://en.cppreference.com/w/cpp/language/move_constructor

しかし、以下のサンプルでは、​​DeepData2の暗黙のコンストラクターに依存すると、ポインター_IMPORTANT_DATAの二重削除が原因でクラッシュすることを示しています。DeepData2のmoveコンストラクターを明示的にすると、コードは正常に実行されます。

私はそれをする必要がなく、暗黙の移動コンストラクターに依存できることを望んでいました。そうでなければ、追加のコンストラクターと割り当てを提供することを覚えておく必要があるのはユーザーコードの負担のようです。DeepData2が明示的な移動コンストラクターを確実に必要とする必要がある場合、ユーザーコードがコンストラクターを提供し忘れた場合にエラーにすることができますか?明示的な移動コンストラクターを持つメンバーが原因で、テンプレートタイプが明示的な移動コンストラクターを必要とするかどうかを検出する方法はありますか?stdタイプの特性を使用すると、「ユーザーコード、テンプレートarg Tの場合、移動セマンティクスが必要で忘れてしまった」などの適切なアサーションを作成するのに十分な情報が得られないようです。

これは複雑です。アドバイスや助けをありがとう

#include "stdafx.h"

#include <vector>
#include <algorithm>
#include <iostream>


template <typename T>
class DeepVector
{
public:
    DeepVector()
    {
        deepCopyResize(4);
    }

    void push_back(T& v)
    {
        if (_capacity <= _count)
        {
            deepCopyResize(_capacity * 2);
        }

        // !! deep copy desired here !!
        _data[_count++] = std::move(v);
    }

    T& operator[](int i) { return _data[i];  }

    void deepCopyResize(int cap)
    {
        int n = std::min(_count, cap);
        T* d = new T[cap];
        if (_data)
        {
            for (int i = 0; i < n; ++i)
            {
                // !! deep copy desired here !!
                d[i] = std::move(_data[i]);
            }
            delete[] _data;
        }
        _data = d; 
        _capacity = cap; 
        _count = n;
    }
private:

    int _capacity = 0;
    int _count = 0;
    T* _data = nullptr; 
};


struct FlatData1
{
    int x = 0, y = 0; 
};

struct DeepData1
{
    DeepData1()
    {

    }

    DeepData1(int s)
    {
        _size = s;
        _IMPORTANT_DATA = new int[_size];
    }

    // move constructor
    DeepData1(DeepData1&& rhs)
    {
        _size = rhs._size;
        _IMPORTANT_DATA = rhs._IMPORTANT_DATA;  // pilfer
        rhs._size = 0;
        rhs._IMPORTANT_DATA = nullptr;
    }

    // move operator
    DeepData1& operator=(DeepData1&& rhs)
    {
        _size = rhs._size;
        _IMPORTANT_DATA = rhs._IMPORTANT_DATA; // pilfer
        rhs._size = 0;
        rhs._IMPORTANT_DATA = nullptr;
        return *this;
    }

    ~DeepData1()
    {
        if (_IMPORTANT_DATA)
        {
            std::cout << "non-trivial destructor" << std::endl;
            _size = 0; 

            // it is an error to delete important twice
            delete[] _IMPORTANT_DATA;
            _IMPORTANT_DATA = NULL;
        }
    }
    int _size = 0; 
    int* _IMPORTANT_DATA = nullptr; 

    void resize(int s)
    {
        delete[] _IMPORTANT_DATA; 
        _IMPORTANT_DATA = new int[s];
        _size = s;
    }
};

struct DeepData2
{
    int z = 0; 
    DeepData1 problem;     // this data does not deep copy implicitly ?

    //  DeepData2() {} 

//   despite C++ standard forcing default not supported by VS2013
//    DeepData2(DeepData2&&) = default;


//    DeepData2(int s) : problem(s) {}
    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    // where are my implicit move constructors?

    // I have to uncomment these for the 
    // DeepData::operator=(DeepData&& rhs)
    // operator to be called 

    /*
     // have to manually implement move constructor?
     DeepData2(DeepData2&& rhs)
     {
     z = std::move(rhs.z);
     problem = std::move(rhs.problem);
     }

     // move operator
     DeepData2& operator=(DeepData2&& rhs)
     {
     z = std::move(rhs.z);
     problem = std::move(rhs.problem);
     return *this;
     }
   */

    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
};


int _tmain(int argc, _TCHAR* argv[])
{

    // ----------------------------------------------
    DeepVector<int> v1; 
    for (int i=0; i<5; ++i)
    { 
        v1.push_back(i);
    }

    if (v1[4] == 4)
    {
        std::cout << "resize 1 worked" << std::endl;
    }

    // ----------------------------------------------
    DeepVector<FlatData1> v2;
    for (int i = 0; i < 5; ++i)
    {
        v2.push_back(FlatData1());
        v2[i].x = i;
        v2[i].y = i;
    }

    if (v2[4].x == 4)
    {
        std::cout << "resize 2 worked" << std::endl;
    }

    // ----------------------------------------------
    DeepVector<DeepData1> v3;
    for (int i = 0; i < 5; ++i)
    {
        v3.push_back(DeepData1(10));

    }

    if (v3[4]._size == 10)
    {
        std::cout << "resize 3 worked" << std::endl;
    }


    // ----------------------------------------------


    bool b1 = std::is_move_constructible<DeepData1>();
    bool b2 = std::is_move_assignable<DeepData1>();
    bool b3 = std::is_trivially_move_assignable<DeepData1>();
    bool b4 = std::is_trivially_move_constructible<DeepData1>();

    bool b5 = std::is_move_constructible<DeepData2>();
    bool b6 = std::is_move_assignable<DeepData2>();

    // VS2013 says DeepData2 is trivially moveable with the implicit constructors
    bool b7 = std::is_trivially_move_assignable<DeepData2>();
    bool b8 = std::is_trivially_move_constructible<DeepData2>();

    DeepVector<DeepData2> v4;
    for (int i = 0; i < 5; ++i)
    {
        DeepData2 d2;
        d2.problem.resize(10);
        v4.push_back(d2); 
    }

    if (v4[4].problem._size == 10)
    {
        std::cout << "resize 4 worked" << std::endl;
    }


    return 0;
}
Yakk-Adam Nevraumont

MSVC2013は、生成または=default移動コンストラクター(または代入演算子)をサポートしていません

MSVC2015はそうします。実際のC ++ 11コンパイラであるために欠けている主なコンポーネントは、「式SFINAE」の失敗と呼ばれるものです。

MSVC2013およびC ++ 11での作業は、コンパイラーを交換しないと不可能です。C ++ 03とそれがサポートするC ++ 11の部分のハイブリッドでプログラミングできます。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

テンプレート引数でstd :: functionを使用する方法

分類Dev

テンプレートでjsデータを使用する方法は?

分類Dev

テンプレート間でデータを渡す方法meteorjs

分類Dev

gohtmlテンプレートにデータを送信する方法

分類Dev

テンプレートにデータを表示する方法

分類Dev

C ++でのテンプレートイテレータの使用std :: map

分類Dev

FlaskテンプレートでMQTTデータを表示する

分類Dev

テンプレートビューでredisjsonデータを表示する方法pythondjango

分類Dev

std :: bindでテンプレート関数パラメータを使用する方法は?

分類Dev

GoLangでJsonデータをHTMLテンプレートにマップする

分類Dev

Goでテンプレートにデータを自動的に渡す方法は?

分類Dev

テンプレート間でデータを渡す

分類Dev

std :: void_tでクラステンプレートを使用してデフォルトのコンストラクターを確認する

分類Dev

テンプレートを使用して表形式でデータを表示する

分類Dev

テンプレートでstd :: functionを使用する

分類Dev

C ++のテンプレートクラスからstd :: vectorデータにアクセスする方法

分類Dev

データテンプレートなしでKendoUIMultiselectを使用する-Angular2 +

分類Dev

WPFのデータテンプレートでトリガーを使用する方法

分類Dev

テンプレートにデータを動的にロードする方法は?

分類Dev

たとえば、std :: vector <std :: string>またはstd :: map <std :: tree>に特化できるクラスのテンプレートテンプレートパラメータを使用したテンプレート定義

分類Dev

パンダでデータフレームをループするときにif / elseステートメントを使用する最速の方法

分類Dev

テンプレートのデフォルトパラメータとしてstd :: vectorを設定するにはどうすればよいですか?

分類Dev

djangoテンプレート言語でテンプレートに表示されたデータを別の方法で取得する方法

分類Dev

テンプレート関数パラメーターでstd :: bindを使用する

分類Dev

データパイプラインでテストデータセットをトレーニングする

分類Dev

さまざまなビューでエディターテンプレートを使用する方法

分類Dev

Angularディレクティブテンプレートに条件付きでデータ属性を追加する

分類Dev

テンプレートにデータを表示する

分類Dev

ejsテンプレートにデータを表示する

Related 関連記事

  1. 1

    テンプレート引数でstd :: functionを使用する方法

  2. 2

    テンプレートでjsデータを使用する方法は?

  3. 3

    テンプレート間でデータを渡す方法meteorjs

  4. 4

    gohtmlテンプレートにデータを送信する方法

  5. 5

    テンプレートにデータを表示する方法

  6. 6

    C ++でのテンプレートイテレータの使用std :: map

  7. 7

    FlaskテンプレートでMQTTデータを表示する

  8. 8

    テンプレートビューでredisjsonデータを表示する方法pythondjango

  9. 9

    std :: bindでテンプレート関数パラメータを使用する方法は?

  10. 10

    GoLangでJsonデータをHTMLテンプレートにマップする

  11. 11

    Goでテンプレートにデータを自動的に渡す方法は?

  12. 12

    テンプレート間でデータを渡す

  13. 13

    std :: void_tでクラステンプレートを使用してデフォルトのコンストラクターを確認する

  14. 14

    テンプレートを使用して表形式でデータを表示する

  15. 15

    テンプレートでstd :: functionを使用する

  16. 16

    C ++のテンプレートクラスからstd :: vectorデータにアクセスする方法

  17. 17

    データテンプレートなしでKendoUIMultiselectを使用する-Angular2 +

  18. 18

    WPFのデータテンプレートでトリガーを使用する方法

  19. 19

    テンプレートにデータを動的にロードする方法は?

  20. 20

    たとえば、std :: vector <std :: string>またはstd :: map <std :: tree>に特化できるクラスのテンプレートテンプレートパラメータを使用したテンプレート定義

  21. 21

    パンダでデータフレームをループするときにif / elseステートメントを使用する最速の方法

  22. 22

    テンプレートのデフォルトパラメータとしてstd :: vectorを設定するにはどうすればよいですか?

  23. 23

    djangoテンプレート言語でテンプレートに表示されたデータを別の方法で取得する方法

  24. 24

    テンプレート関数パラメーターでstd :: bindを使用する

  25. 25

    データパイプラインでテストデータセットをトレーニングする

  26. 26

    さまざまなビューでエディターテンプレートを使用する方法

  27. 27

    Angularディレクティブテンプレートに条件付きでデータ属性を追加する

  28. 28

    テンプレートにデータを表示する

  29. 29

    ejsテンプレートにデータを表示する

ホットタグ

アーカイブ