C ++コードを最新化するのは簡単です

こんにちは、Habr!



C ++コードで冗長なレガシーを処理することに関する短い実用的な記事の翻訳に注意を向けます。おもしろいことを願っています。



最近、C ++コミュニティは、新しい標準の使用と既存のコードベースの最新化を積極的に推進しています。ただし、C ++ 11標準がリリースされる前でさえ、Andre Alexandrescu、Scott Myers、HerbSutterなどの有名なC ++専門家は、一般的なC ++プログラミングを推進し、「最新のC ++デザイン」と認定しました。アンドレ・アレクサンドレスクはそれを次のように述べています。



最新のC ++デザインは、汎用コンポーネントを定義し、体系的に使用します。これは、非常に柔軟なデザインアーティファクトであり、組み合わせて組み合わせると、小さな直交するコードで豊富な動作を生成できます。


この論文では、次の3つのステートメントが興味深いです。



  • 最新のC ++デザインは、汎用コンポーネントを定義し、体系的に使用します
  • 非常に柔軟なデザイン。
  • 小さな直交するコードでリッチな動作を実現します。


C ++で記述されたコードの最新化には、新しい標準の導入だけでなく、コードベースの改善に役立つ任意のプログラミング言語に適用可能なベストプラクティスの使用も含まれます。まず、コードベースを手動でアップグレードするための簡単な手順について説明します。3番目のセクションでは、自動コードアップグレードについて説明します。



ソースコードを手動で更新する



例としてアルゴリズムを取り上げて、それを最新化してみましょう。アルゴリズムは、計算、データ処理、および結論の自動導出に使用されます。アルゴリズムのプログラミングは、重要なタスクである場合があり、その複雑さに依存します。C ++では、実装を簡素化し、アルゴリズムの能力を高めるために多大な努力が払われています。

クイックソートアルゴリズムのこの実装を最新化してみましょう。



//  
int partition(int* input,int p,int r){
        int pivot = input[r];
        while( p < r ){
                 while( input[p]< pivot )
                     p++;
                 while( input[r]> pivot )
                    r--;
                if( input[p]== input[r])
                    p++;
                elseif( p < r ){
                     int tmp = input[p];
                     input[p]= input[r];
                     input[r]= tmp;
                }
        }
         return r;
}
//    
void quicksort(int* input,int p,int r){
        if( p < r ){
              int j = partition(input, p, r);        
              quicksort(input, p, j-1);
              quicksort(input, j+1, r);
        }
}

      
      





結局のところ、すべてのアルゴリズムには特定の共通点があります。



  • 特定のタイプの要素にコンテナを使用し、それらを繰り返し処理します。
  • 要素の比較
  • 要素に対するいくつかの操作


この実装では、コンテナは整数の生の配列であり、インクリメント操作とデクリメント操作を1つずつ繰り返します。比較はとを使用 “<”



して “>”



実行されます。また、データに対していくつかの操作を実行します。たとえば、データを交換します。



アルゴリズムのこれらの各機能を改善してみましょう。



ステップ1:コンテナーをイテレーターに変更する



一般的なコンテナを放棄すると、特定のタイプの要素のみを使用するように強制されます。同じアルゴリズムを他のタイプに適用するには、コードをコピーして貼り付ける必要があります。汎用コンテナはこの問題を解決し、あらゆる種類の要素を使用できるようにします。たとえば、クイックソートアルゴリズムでstd::vector<T>



は、生の配列の代わりにコンテナとして使用できます



生の配列または std::vector



は、多くの要素を表すさまざまなオプションの1つにすぎません。同じアルゴリズムが、リンクリスト、キュー、またはその他のコンテナに適用されます。イテレーターを使用する場合は、使用するコンテナーを抽象化するのが最適です。



イテレーターは、特定の範囲内の要素を指し、一連の演算子(少なくとも、1つの演算子(++)と逆参照演算子(*)による増分を含む)を使用して、指定された範囲のすべての要素を反復処理できるオブジェクトです。イテレーターは、実行する機能に基づいて、入力、出力、一方向イテレーター、双方向イテレーター、およびランダムアクセスの5つのカテゴリに分類されます。



このアルゴリズムでは、使用するイテレーターを指定する必要があります。これを行うには、使用している反復を識別する必要があります。クイックソートアルゴリズムは、1ずつ増加し、1ずつ減少する反復を使用します。したがって、双方向のイテレーターが必要です。イテレーターを使用すると、次のようなメソッドを定義できます。



template< typename BidirectionalIterator >
void quick_sort( BidirectionalIterator first, BidirectionalIterator last )
      
      





ステップ2:可能であれば、コンパレータを一般化する



一部のアルゴリズムでは、数値だけでなく、文字列やクラスなども処理する必要があります。この場合、コンパレータを一般化する必要があります。これにより、アルゴリズム全体のより大きな一般化を実現できます。



クイックソートアルゴリズムは、文字列のリストにも適用できます。したがって、一般化されたコンパレータの方が適しています。



一般化されたコンパレータを使用して、次のように定義を変更できます。



template< typename BidirectionalIterator, typename Compare >
void quick_sort( BidirectionalIterator first, BidirectionalIterator last, Compare cmp )
      
      





ステージ3:既存の操作を標準の操作に置き換えます



ほとんどのアルゴリズムは、次のような繰り返し動作を使用し min



max



そして swap



このような操作を実行するときは、ホイールを作り直さずに、ヘッダーに存在する標準の実装を使用することをお勧めし <algorithm>



ます。



この場合、独自のメソッドを作成する代わりに、STL標準ライブラリのswapメソッドを使用できます。



std::iter_swap( pivot, left );
      
      





そして、これらの3つのステップの後に変更された結果は次のとおりです。



#include <functional>
#include <algorithm>
#include <iterator>
 
template< typename BidirectionalIterator, typename Compare >
void quick_sort( BidirectionalIterator first, BidirectionalIterator last, Compare cmp ) {
    if( first != last ) {
        BidirectionalIterator left  = first;
        BidirectionalIterator right = last;
        BidirectionalIterator pivot = left++;
 
        while( left != right ) {
            if( cmp( *left, *pivot ) ) {
                ++left;
            } else {
                while( (left != right) && cmp( *pivot, *right ) )
                    --right;
                std::iter_swap( left, right );
            }
        }
 
        --left;
        std::iter_swap( pivot, left );
 
        quick_sort( first, left, cmp );
        quick_sort( right, last, cmp );
    }
}
 
template< typename BidirectionalIterator >
    inline void quick_sort( BidirectionalIterator first, BidirectionalIterator last ) {
        quick_sort( first, last,
                std::less_equal< typename std::iterator_traits< BidirectionalIterator >::value_type >()
                );
    }
      
      





この実装には、次の利点があります。



  • あらゆる種類の要素に適用できます。
  • コンテナは、ベクトル、セット、リスト、または双方向イテレータを備えたその他のものにすることができます。
  • この実装では、最適化およびテストされた標準関数を使用します。


自動アップグレード



C ++ 11 / C ++ 14 / C ++ 17の特定の機能を使用できる場所を自動的に識別し、条件が良好な場合は、コードを自動的に変更するのは興味深いことです。このような目的のために、古い標準に従って記述されたC ++コードを自動的に変換するために使用されるフル機能のclang-tidyツール があります。このような変換後、コードは必要に応じて新しい標準の機能を使用します。



clang-tidyがコードのアップグレードを提案するいくつかの領域は次のとおりです。



  • オーバーライド:基本クラスの仮想関数をまだ持っていなくてもオーバーライドするインスタンス関数のオーバーライドポインターを追加できる場所を見つけます
  • : for(…; …; …)



    , , , .
  • : const-ref



    , .
  • auto_ptr



    : std::auto_ptr



    std::unique_ptr



    .
  • -: , auto



    .
  • nullptr



    : , nullptr



    , .
  • std::bind



    : std::bind , , . , , .
  • : C C++ . C++. C++ 14 [depr.c.headers].
  • std::shared_ptr



    : std::shared_ptr



    new



    , std::make_shared



    .
  • std::unique_ptr



    : std::shared_ptr



    new



    , std::make_unique



    , C++14.
  • : , , .


Clangをマスターした開発者は、clang-tidyツールの使い方を簡単に学ぶことができます。ただし、Visual C ++や他のコンパイラを使用する場合は、clang-tidyを含むCppDependを使用できます



All Articles