web-dev-qa-db-ja.com

新しいキーワード「auto」。変数型を宣言するためにいつ使用する必要がありますか?

可能性のある複製:
C++ 0x autoキーワードではどれくらいの大きさですか

(コミュニティとして)私たちは、自動車がいつ悪用されているかを判断するのに十分な経験がありますか?

私が本当に探しているのは、ベストプラクティスガイドです

  • 自動を使用する場合
  • 避けるべき時

ケースの80%ですぐに従うことができる簡単な経験則。

コンテキストとして、この質問は私の応答によって引き起こされます here

84
Martin York

タイプがプロジェクトで働く(または働く)プログラマーの間で非常によく知られている場合、次のコードのようにautoを使用できると思います。

//good : auto increases readability here
for(auto it = v.begin(); it != v.end(); ++it) //v is some [std] container
{
      //..
}

または、より一般的には、

//good : auto increases readability here
for(auto it = std::begin(v); it != std::end(v); ++it)//v could be array as well
{
      //..
}

ただし、型があまり知られておらず、あまり使用されていない場合は、次のようにautoが読みやすさを低下させると思われます。

//bad : auto decreases readability here
auto obj = ProcessData(someVariables);

前者の場合、autoの使用は非常に良いようで、読みやすさを低下させないため、広範囲に使用できますが、後者の場合、読みやすさを低下させるため、使用しないでください。


autoを使用できる別の場所は、newを使用するときです1 または make_*関数、ここなど:

//without auto. Not that good, looks cumbersome
SomeType<OtherType>::SomeOtherType * obj1 = new SomeType<OtherType>::SomeOtherType();
std::shared_ptr<XyzType> obj2 = std::make_shared<XyzType>(args...);
std::unique_ptr<XyzType> obj2 = std::make_unique<XyzType>(args...);

//With auto. good : auto increases readability here
auto obj1 = new SomeType<OtherType>::SomeOtherType();
auto obj2 = std::make_shared<XyzType>(args...);
auto obj3 = std::make_unique<XyzType>(args...);

ここでは、コードを見るだけで誰でもobjectsが作成されていることを知ることができるため、読みやすさを損なうことなくキーボードの使用を減らすため、非常に優れています。

1. newとrawポインターの使用は避けてください。


expression template;のように、型があまり重要ではないため、型の知識は必要ありません。実際、実際には型を(正しく)書くことは不可能です。そのような場合、autoはプログラマにとって安心です。次のように使用できる式テンプレートライブラリを作成しました。

foam::composition::expression<int> x;

auto s = x * x;       //square
auto c = x * x * x;   //cube
for(int i = 0; i < 5 ; i++ )
    std::cout << s(i) << ", " << c(i) << std::endl; 

出力:

0, 0
1, 1
4, 8
9, 27
16, 64

上記のコードを次の同等autoを使用しないコードと比較します。

foam::composition::expression<int> x;

//scroll horizontally to see the complete type!!
foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<int>, foam::composition::expression<int>, foam::operators::multiply>> s = x * x; //square
foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<foam::composition::details::binary_expression<foam::composition::expression<int>, foam::composition::expression<int>, foam::operators::multiply> >, foam::composition::expression<int>, foam::operators::multiply>> c = x * x * x; //cube

for(int i = 0; i < 5 ; i++ )
    std::cout << s(i) << ", " << c(i) << std::endl; 

ご覧のように、そのような場合、autoはあなたの人生を指数関数的に簡単にします。上記で使用される式は非常に単純です。より複雑な式のタイプについて考えてみましょう。

auto a = x * x - 4 * x + 4; 
auto b = x * (x + 10) / ( x * x+ 12 );
auto c = (x ^ 4 + x ^ 3 + x ^ 2 + x + 100 ) / ( x ^ 2 + 10 );

そのような式のタイプはさらに大きくていものになりますが、autoのおかげで、コンパイラに式のタイプを推測させることができます。


つまり、キーワードautoは、増減コードの明快さと読みやすさ、コンテキストに応じてです。コンテキストがtypeが何であるか、少なくともそれがどのように使用されるべきか(標準のコンテナイテレータの場合)、または実際の型の知識さえ必要ない場合(式など)テンプレート)、autosedである必要があり、コンテキストが明確にせず、あまり一般的でない場合(上記の2番目のケースなど)、 be 回避

142
Nawaz

簡単です。 do n't careタイプの場合に使用します。例えば

_for (auto i : some_container) {
   ...
_

ここで気にするのは、iがコンテナの中にあるものだけだということです。

Typedefに少し似ています。

_typedef float Height;
typedef double Weight;
//....
Height h;
Weight w;
_

ここでは、hwがfloatであるかdoubleであるかは関係なく、それらが身長と体重を表すのに適したタイプであれば何でもかまいません

または考慮する

_for (auto i = some_container .begin (); ...
_

ここで私が気にするのは、それがoperator++()をサポートする適切なイテレータであるということだけです。

また、ラムダの種類は綴ることができないため、_auto f = []..._は良いスタイルです。別の方法は_std::function_にキャストすることですが、これにはオーバーヘッドが伴います。

私はautoの「乱用」を本当に想像することはできません。私が想像できる最も近いのは、何らかの重要な型への明示的な変換を自分自身から奪うことです-しかし、そのためにautoを使用せずに、目的の型のオブジェクトを構築します。

can副作用を引き起こすことなくコードの冗長性を削除する場合、mustそうするのが良い。

16
spraff

C#のvarと同じルールを適用します:それを自由に使用します。それは可読性を高めます。変数の型が実際に明確に述べられるほど重要でない限り、その場合はこれを行う必要があります(duh)。

それでも、(特に静的に型付けされた言語では)コンパイラは、私たちよりも型を追跡するのがはるかに優れていると主張しています。ほとんどの場合、exactタイプはとにかくそれほど重要ではありません(そうでなければ、インターフェースは実際には機能しません)。どの操作が許可されているかを認識することがより重要です。コンテキストはそれを教えてくれるはずです。

さらに、autoは実際にバグを防ぐことができます、初期化での不要な暗黙の変換を防止します。一般的に、ステートメントFoo x = y;は、yFoo型ではなく、暗黙的な変換が存在する場合、暗黙的な変換を実行します。これが、最初の暗黙的な変換を避けるための理由です。残念ながら、C++には既にそれらの多くがあります。

auto x = y;は原則的にこの問題を防ぎます

一方、整数のこのバイト数またはそのバイト数を想定して計算を実行する場合、変数の明示的な型を知っておく必要があり、明確に述べる必要があることは明らかです。

すべてのケースが明確なわけではありませんが、私はそれがほとんどであり、

  1. ほとんどの場合、明示的な型を知る必要があるかどうかを簡単に確認できます。
  2. 明示的な型の必要性は比較的まれです。

Eric Lippert 、C#コンパイラチームの主な開発者 varに関してほぼ同じことを述べています

14
Konrad Rudolph

あなたの最初の質問に対する答えはある種のノーだと思います。 autoを使用または回避するタイミングに関するガイドラインをまとめるのに十分なことはわかっていますが、現時点で言えることは、まだ多くのことを客観的に与えることができないということですそれらについてのアドバイス。

ほぼhaveを使用する明らかなケースは、2つの汎用パラメーターに対する何らかの操作の結果を保持する適切な型を(たとえば)必要とする場合のテンプレートです。このような場合、乱用の唯一の可能性は、実際にはauto自体の乱用ではなく、あなたがしている一般的なタイプの操作(または書いているテンプレートのタイプなど)避けた方が良いと思います。

autoを避ける必要があることが明らかに必要な状況も少なくともいくつかあります。プロキシタイプのようなものを使用していて、プロキシからターゲットへの変換に依存している場合、autoは同じタイプのターゲットを作成(試行)します。ソースとして、変換が発生しないようにします。場合によっては、変換が遅れるだけかもしれませんが、まったく機能しない場合もあります(たとえば、プロキシタイプが割り当てをサポートしていない場合など、よくあります)。

別の例は、外部インターフェースのようなもののために特定の変数が特定の型を持つことを保証する必要がある場合です。たとえば、ネットワークマスクをIP(v4)アドレスに適用することを検討してください。引数のために、アドレスの個々のオクテットで作業していると仮定しましょう(たとえば、それぞれをunsigned char)、したがって、octets[0] & mask[0]。 Cの型昇格規則のおかげで、たとえ両方のオペランドがunsigned chars、通常、結果はintになります。 必要結果はunsigned charしかし(つまり、1オクテット)int(通常は4オクテット)ではありません。そのため、この状況では、autoはほぼ間違いなく不適切です。

しかし、それでも判断が必要なケースが多く残っています。私自身のtendencyは、これらのケースでautoをデフォルトとして扱い、少なくとも上で引用した後者のケースに少し似たケースでのみ明示的な型を使用します- -特定の型がneededでなくても、正しい操作のためにwant特定の型であっても、暗黙の変換を伴う場合があります。

私の推測(しかし、それは単なる推測です)は、時間が経つにつれて、私はおそらくがその方向にさらに向かう傾向があることです。コンパイラが型を選択することに慣れてくると、現在思考を指定しなければならないかなりの数のケースが見つかります。実際に型を指定する必要はなく、コードは元気です.

私たちの多く(そして、私たちが年をとる/経験を積む、おそらくもっと悪い)は、最終的にパフォーマンスについての感覚にまでさかのぼる理由で明示的な型を使用し、私たちの選択がパフォーマンスを改善すると信じている。一部の時間mayさえ正しい-しかし、その多くの経験がある私たちのほとんどが発見したように、私たちの推測はしばしば間違っています(特に暗黙の仮定に基づいている場合)、そしてコンパイラとプロセッサーは一般に、時間の経過とともにそのようなことでも良くなります。

4
Jerry Coffin

完全な型推論を持つ言語を使用しました。 autoを技術的に可能なすべての場所に配置しない理由はありません*。実際、私はすでにauto i = 0;、ここでintautoより1文字短いです。ボトムがマニフェストのタイピングを気にしないので、私がしたことすらわからない。

*: 例えば auto int[] = { 0, 1, 2, 3 }は機能しません。

2
Luc Danton

長いテンプレートやラムダ関数型などの長い繰り返し型でのみ使用してください。あなたが物事を明確にすることができるなら、それを避けるようにしてください。

2
Will03uk