C ++でautoを使用して変数を宣言することの欠点はありますか?


143

これはauto、C ++ 11に追加されるかなり重要な機能であり、多くの新しい言語に従っているようです。Pythonのような言語と同様に、明示的な変数宣言はありません(Python標準を使用して可能かどうかはわかりません)。

auto変数を明示的に宣言する代わりにを使用して宣言することに欠点はありますか?


1
次も参照:stackoverflow.com/questions/6434971/…、stackoverflow.com / questions / 15254461 /…、stackoverflow.com / questions / 6900459 /…、stackoverflow.com / questions / 8430053 / is-c11-auto-type-dangerous、そしておそらく他のもの。これらが完全に重複しているかどうかはわかりませんが、間違いなく候補です。
コーディグレイ

3
私が見つけた唯一の欠点は、コンパイラがC ++ 11機能をサポートしていない(そしてサポートするつもりがなかった)(コンソール)プラットフォームにコードベースを移植する必要があったときです!
Sam

7
ただ、完全GotW#94「ほとんど常にオート」について:herbsutter.com/2013/08/12/...
リチャードCritten

1
私はcppcastを聞いていましたが、b / w自動クラッシュとリスト初期化子のクラッシュについての言及がありました。そのポッドキャストを探してみます。
Abhinav Gauniyal

2
最初のマイナス面は、コードの読みやすさに影響を与えると思います
ggrr

回答:


111

あなたは欠点についてのみ尋ねてきたので、それらのいくつかを強調します。うまく使用すると、autoいくつかの利点もあります。欠点は、乱用のしやすさと、コードが意図しない方法で動作する可能性が高まることに起因します。

主な欠点は、を使用してもauto、作成されるオブジェクトのタイプが必ずしもわかるとは限らないことです。また、プログラマーがコンパイラーがあるタイプを推定することを期待するかもしれませんが、コンパイラーは固く別のタイプを推定する場合もあります。

のような宣言が与えられた

auto result = CallSomeFunction(x,y,z);

必ずしもタイプresultが何であるかを知っている必要はありません。かもしれませんint。ポインタかもしれません。それは何か他のものかもしれません。これらはすべて、さまざまな操作をサポートしています。次のような小さな変更でコードを劇的に変更することもできます

auto result = CallSomeFunction(a,y,z);

CallSomeFunction()結果のタイプに存在するオーバーロードによっては、完全に異なる可能性があるため、後続のコードは意図したものとはまったく異なる動作をする可能性があるためです。後のコードでエラーメッセージを突然トリガーする可能性があります(たとえば、後でを逆参照しようとするint、現在のを変更しようとするconst)。より不吉な変更とは、変更がコンパイラを通過するところですが、後続のコードは異なる方法で動作します。

したがって、一部の変数のタイプを明確に把握していないと、コードが意図したとおりに機能するという主張を厳密に正当化することが難しくなります。これは、重要性の高い(たとえば、安全性が重要な、またはミッションクリティカルな)ドメインで「目的に合っている」という主張を正当化するためのさらなる努力を意味します。

もう1つのより一般的な欠点はauto、コードが何をしているのかを考えて正しく理解するのではなく、プログラマーが率直な手段としてコードを強制的にコンパイルさせる誘惑です。


58
そのような例がを使用することの欠点である場合auto、ほとんどのアヒル型言語はそのような欠点を設計上抱えていることに注意するのは興味深いことです。
Leben Asa

11
CallSomeFunction()引数のシーケンスに応じて異なるタイプを返す場合、それはの設計上の欠陥でCallSomeFunction()あり、の問題ではありませんauto。使用する前に使用している関数のドキュメントを読んでいない場合、それはプログラマーの欠陥であり、の問題ではありませんauto。-しかし、あなたはここで悪魔の支持者を演じていると理解しています。
DevSolar

16
@DevSolar:なぜT CallSomeFunction(T, int, int)設計に欠陥があるのですか?明らかに、「引数のシーケンスに応じて異なる型を返します」。
MSalters

9
「主な欠点は、を使用してもauto、作成されるオブジェクトのタイプが必ずしもわかるとは限らないことです。」なぜこれがの問題でありauto、部分式の一時の問題ではないのか、詳しく説明できますか?なぜauto result = foo();悪いのfoo().bar()ですか?
Angewはもはや誇りSOのではありません

24
コメントから、「欠点」は何かが受け入れられない理由として解釈されているようです。言語機能の欠点は、開発者が受け入れるかどうかを検討して正当化する必要がある、つまりエンジニアリングのトレードオフを行う必要があるという欠点です。この機能を使用する理由と使用しない理由について、全面的な主張はしていません。
Peter

76

これはauto原理的には欠点ではありませんが、実際には一部の人にとって問題となるようです。基本的に、一部の人々は次のいずれかを行います:a)autoタイプの救世主として扱い、それを使用するときに脳を遮断するか、またはb)auto常に値タイプを推測することを忘れます。これにより、人々はこのようなことをします:

auto x = my_obj.method_that_returns_reference();

おっと、オブジェクトをディープコピーしただけです。多くの場合、バグかパフォーマンスの失敗です。次に、反対方向にも振ることができます。

const auto& stuff = *func_that_returns_unique_ptr();

これで、ぶら下がっている参照を取得します。これらの問題はまったく原因ではないautoので、それらに対する正当な議論とは見なしません。しかしauto、冒頭に挙げた理由により、(個人的な経験から)これらの問題がより一般的になるように思われます。

人々が時間を調整し、分業を理解することを考えるautoと、基になるタイプを推定しますが、参照性と定数性についてはまだ考えたいと思います。しかし、少し時間がかかります。


最初に高価なオブジェクトをディープコピーできるのはなぜですか?
Laurent LA RIZZA

3
@LaurentLARIZZA:一部のクラスには、時々必要になるだけの理由でコピーコンストラクターがあります(例:のインスタンスstd::vector)。コピーにコストがかかるのはクラスのプロパティではなく、個々のオブジェクトのプロパティです。したがってmethod_that_returns_reference、コピーコンストラクターを持つクラスのオブジェクトを参照する可能性がありますが、どのオブジェクトをコピーするのが非常にコストがかかります(移動できない)。
Marc van Leeuwen

@MarcvanLeeuwen:オブジェクトのコピーにコストがかかり、移動できない場合、なぜオブジェクトがstd::vector?(可能性があります、そう、またはクラスを制御しないためですが、それはポイントではありません)コピーするのにコストがかかる場合(そしてコピー可能であるためリソースを所有しない場合)、オブジェクトでCOWを使用しないのはなぜですか?オブジェクトのサイズにより、データの局所性はすでに失われています。
Laurent LA RIZZA

2
@LaurentLARIZZA高価なベクターに格納されているもののインスタンスではなく、通常の例えばvector <double>はコピーにコストがかかります。これはヒープ割り当て+ O(N)の作業です。引っ越しは赤いニシンです。返された参照が右辺値参照でない限り、最初に表示した行は移動ではなくコピーされます。COWは本当にここにもそこにもありません。実際には、オブジェクトをコピーするにはコストがかかります。
Nir Friedman

4
@Yakkスライスする可能性があるため、それを安全に行うことはできません。それができる唯一の安全なことは= delete、その過負荷です。より一般的には、あなたが言うことは解決策です。これは、興味があれば私が調べたトピックです:nirfriedman.com/2016/01/18/…
Nir Friedman

51

他の回答は、「変数の型が何であるか本当にわからない」のような欠点について言及しています。これは主に、コードのずさんな命名規則に関連していると思います。インターフェースに明確な名前が付けられている場合は、正確なタイプを気にする必要はありません。わかりauto result = callSomeFunction(a, b);ません。しかし、その正確なタイプが何であるかを気auto valid = isValid(xmlFile, schema);にするvalidことなく使用するのに十分です。結局のところ、だけif (callSomeFunction(a, b))では、型もわかりません。他の部分式一時オブジェクトと同じです。だから私はこれを本当の欠点とは考えていませんauto

その主な欠点は、正確な戻り値の型が操作したいものと異なる場合があることです。実際、実際の戻り値の型は、実装/最適化の詳細として「論理」戻り値の型と異なる場合があります。式テンプレートはその代表的な例です。これがあるとしましょう:

SomeType operator* (const Matrix &lhs, const Vector &rhs);

論理的には、になることSomeTypeを期待しておりVector、コードではそれを間違いなくそのように扱いたいと考えています。ただし、最適化のために、使用している代数ライブラリが式テンプレートを実装している可能性があり、実際の戻り値の型は次のとおりです。

MultExpression<Matrix, Vector> operator* (const Matrix &lhs, const Vector &rhs);

さて、問題は、MultExpression<Matrix, Vector>おそらくconst Matrix&とをconst Vector&内部に保存することです。Vector完全な式の終わりの前にa に変換されることを期待しています。このコードがあれば、問題はありません。

extern Matrix a, b, c;
extern Vector v;

void compute()
{
  Vector res = a * (b * (c * v));
  // do something with res
}

ただし、autoここで使用した場合、問題が発生する可能性があります。

void compute()
{
  auto res = a * (b * (c * v));
  // Oops! Now `res` is referring to temporaries (such as (c * v)) which no longer exist
}

3
@NirFriedman確かに強いですが、実際にautoは欠点がほとんどないと私は感じています。また、プロキシなどの他の例には、DSLにあるさまざまな「文字列ビルダー」や類似のオブジェクトが含まれます。
AngewはSO

2
私はauto以前に、特にEigenライブラリーを使用して、式テンプレートに噛まれました。問題はデバッグビルドに表示されないことが多いため、特に注意が必要です。
Dan

1
使用は、auto使用している場合も噛まできるアルマジロの最適化のためのテンプレートメタプログラミングを多用して行列ライブラリを、。幸い、開発者は.eval()関数を追加しました。これを使用して、次の問題を回避できますauto
mtall

2
「インターフェースに明確な名前が付いていれば、正確なタイプを気にする必要はありません。」コンパイラーは、変数の名前を調べてコードの正確さをチェックすることはできません。これが型システムの要点です。盲目的にそれを迂回するのはばかげています!
オービットのライトネスレース2016年

1
@Angew:通常はすぐに使用しているため、一時的な問題ではありません。通常、autoある種の型チェックが含まautoれていません(また、あらゆる場所でスプラッシュすると、他の場所と同じように型の安全性が失われます)。それは良い比較ではありません。
オービットのライトネスレース2016年

13

欠点の1つは、時にはあなたが宣言することができないということであるconst_iteratorautoこの質問から取ったこのコードの例では、通常の(非const)イテレータを取得します。

map<string,int> usa;
//...init usa
auto city_it = usa.find("New York");

3
さて、iteratorあなたの地図はでないので、あなたはどんな場合でもを取得しますconst。これをに変換する場合は、const_iterator通常どおり変数の型を明示的に指定するか、メソッドを抽出して、マップがのコンテキストでconstになるようにしますfind。(私は後者を好みます
。SRP

auto city_it = static_cast<const auto&>(map).find("New York")?または、C ++ 17では、auto city_if = std::as_const(map).find("New York")
Dev Null

11

それはあなたのコードを読むのを少し難しくするか退屈なものにします。そのようなものを想像してみてください:

auto output = doSomethingWithData(variables);

ここで、出力のタイプを把握するには、doSomethingWithData関数の署名を追跡する必要があります。


40
常にではない。たとえばauto it = vec.begin();よりもはるかに読みやすいstd::vector<std::wstring>::iterator it = vec.begin();です。
ジョナサン・ポッター

4
同意した。ユースケースによって異なります。もっと正確だったかもしれない。
Skam 2016年

1
@SeeDartそうです、そのような自動車を使用している人々はそれを間違っています。
lciamp

6
「関数のシグネチャを追跡」、それがマウスのホバーまたはキーの押し離しでない場合(「フォローシンボル」/「宣言に移動」/それが呼び出されたものを問わない)、エディターをさらに設定するか、設定なしでこれを行うことができるIDEに切り替えます...しかし、あなたの主張はまだ有効です。
ハイド

6
チェックインを確認するときに、IDEではなく、diffの小さなのぞき穴に気づいた!autoを使用すると、そのため、読みにくくなります。
JDługosz

10

同じように、この開発者、私は嫌いauto。むしろ、私は人々がどのように誤用するかを嫌いますauto

タイピングを減らすためautoはなく、一般的なコードを書くのを助けるための(強い)意見です。
C ++は、堅牢なコードを記述できるようにすることを目的とする言語であり、開発時間を最小限に抑えることはできません
これはC ++の多くの機能からかなり明白ですが、残念ながら、autoタイピングを減らすような新しい機能のいくつかは、人々がタイピングに怠惰になり始めるべきだと誤解させることがあります。

以前autoは人々がtypedefsを使用していましたが、これはすばらしいことtypedef でした。ライブラリの設計者が戻り値の型を理解できるようにして、ライブラリが期待どおりに機能するようにしたからです。を使用する場合autoそのコントロールをクラスのデザイナーから取り除き、代わりにコンパイラーに型を特定するように依頼します。これにより、最も強力なC ++ツールの1つがツールボックスから削除され、コードが破損するおそれがあります。

あなたが使用している場合、一般的に、autoので、それがあるべきあなたのコードは、のために働くすべての合理的なタイプではないあなたはそれがで動作するはずというタイプを書き留めてあまりにも怠惰だから。auto怠惰を助けるためのツールとして使用する場合、通常はを使用したために発生しなかった暗黙の変換が原因で、プログラムに微妙なバグが発生し始めますauto

残念ながら、これらのバグは、説明することは困難ですが、彼らは一定の期待テンプレート重いコードで発生しやすい-その簡潔さは、それらが少ないユーザーのプロジェクトに出てくる実際の例よりも説得力になるので、ここでは簡単な例では暗黙の型変換を取るために場所。

例が必要な場合は、ここにあります。ただし、少し注意してください。コードをジャンプして批判する前に、そのような暗黙の変換を中心に多くのよく知られた成熟したライブラリが開発されており、不可能ではないにせよ困難な問題解決するために存在しています。そうでなければ解決する。それらを批判する前に、より良い解決策を理解するようにしてください。


3
which was great because typedef allowed the designer of the library to help you figure out what the return type should be, so that their library works as expected. When you use auto, you take away that control from the class's designer and instead ask the compiler to figure out what the type should beIMOの理由はあまりよくありません。たとえば、Visual Studio 2015などの最新のIDEでは、に​​カーソルを合わせると変数の型を確認できますauto。これは、*正確に*と同じtypedef1。
ソンブレロチキン

@JameyD:そこにはいくつかの重要なポイントがありません:(1)IDEの引数は、型がテンプレートではなく具象である場合にのみ機能します。依存型の場合、IDEは正しい型を通知できない場合がありますtypename std::iterator_traits<It>::value_type。(2)全体の要点は、推論された型は、前のコード設計者が意図した正しい型と「完全に同じ」である必要はないということでした。を使用autoすることにより、正しいタイプを指定するデザイナーの機能を奪います。
user541686

あなたは基本的にプロキシについて話しているが、その答えの1つはすでに言及している。式テンプレートとvector <bool>ナンセンスは、ほとんどの人にとって日常的なコードではありません。ほとんどの場合、暗黙の変換は必要ありません。自動変換が役立ちます。Herb Sutterは、彼のブログ投稿の1つで、autoの利点について幅広く語っています。主にキーストロークについてではなく、一般的なコードのためだけのものでもありません。また、あなたが提供した最初のリンクであるブログ投稿は、ひどいアドバイスです(そのため、彼はコメントセクションで激しく批判されています)。
Nir Friedman、

@NirFriedman:"... vector<bool>ナンセンス" ...許し?どのようにbitset実装されていると思いますか?それとも、ビットコンテナーはまったくナンセンスだと思いますか?!
user541686

1
@NirFriedman:vector <bool>についての何も私にとってニュースではありません。私があなたに伝えようとしていること、そしてあなたが露骨に理解することを拒否していることは、この質問の目的ではビットセットはvector <bool>と同じです- プロキシは両方とも有用であると見なされたため、プロキシを使用します、そしてプロキシが有用であるという事実は、否定に生きる代わりに受け入れる必要がある現実です。これをプロキシが有用であるかどうかについての議論に変えるのをやめてください。それは議論の対象ではありません。また、それらについてのあなたの意見は、あなたの意見であり、ある種の事実ではありません。
user541686

6

autoそれ自体には欠点がありません。私は新しいコードのどこでも(手で)使用することを推奨します。これにより、コードで一貫して型チェックを行い、サイレントスライスを常に回避できます。(Bから派生しA、関数がA突然戻るB場合、auto期待どおりに動作して戻り値を格納します)

ただし、C ++ 11より前のレガシーコードは、明示的に型指定された変数の使用によって引き起こされる暗黙的な変換に依存する場合があります。明示的に型指定された変数をにauto変更すると、コードの動作が変わる可能性があるため、注意が必要です。


反対投票は公正ですが、理由についてコメントしていただけますか?
Laurent LA RIZZA 2016年

私はあなたに反対票を投じませんでしたが、autoそれ自体に欠点があります(または少なくとも-多くの人がそうだと思います)。中2番目の質問に与えられた例を検討し、このパネルディスカッションサッター、アレキとマイヤーズでは:あなたが持っている場合auto x = foo(); if (x) { bar(); } else { baz(); }foo()リターンbool-あれば何が起こるfoo()変化は(3つのオプションの代わりに、2)列挙型を返すために?autoコードは動作し続けますが、予期しない結果を生成します。
einpoklum 2017年

@einpoklum:そして、スコープのない列挙型の場合、何かboolauto変更する代わりにを使用しますか?私は間違っているかもしれません(ここでは確認できません)が、唯一の違いはbool、の条件の評価時ではなく、変数宣言時に変換が行われることifです。enumがスコープ指定されている場合、への変換boolは明示的な通知なしには行われません。
Laurent LA RIZZA 2017年

4

キーワードは、auto単に戻り値から型を推定します。したがって、Pythonオブジェクトと同等ではありません。たとえば、

# Python
a
a = 10       # OK
a = "10"     # OK
a = ClassA() # OK

// C++
auto a;      // Unable to deduce variable a
auto a = 10; // OK
a = "10";    // Value of const char* can't be assigned to int
a = ClassA{} // Value of ClassA can't be assigned to int
a = 10.0;    // OK, implicit casting warning

autoはコンパイル時に推定されるため、実行時に何の欠点もありません。


1
はい、それは基本的type()にpythonで何をするかを行います。型を推定し、その型の新しい変数を作成しません。
lciamp

2
@lciamp実際にはそうなりますdecltypeauto特に変数割り当て用です。
2016年

4

これまで誰もここで述べたことはありませんが、あなたが私に尋ねた場合、それ自体は答える価値があります。

C != C++Cで記述されたコードは、C ++コードのベースを提供するように簡単に設計でき、C ++互換性を維持するためにそれほど労力を費やすことなく設計できるので(だれもが知っているはずですが)、これは設計の要件になる可能性があります。

私は、いくつかの明確に定義された構成Cが無効でC++あり、その逆もあるいくつかのルールについて知っています。しかし、これは単に実行可能ファイルが壊れることになり、既知のUB節が適用されます。ほとんどの場合、奇妙なループによってクラッシュまたは何が発生するかが検出されます(または検出されないままになることもありますが、ここでは問題ではありません)。

しかしauto、これが初めて変更されるのは1です!

auto以前にストレージクラス指定子として使用して、コードを転送したとします。それは必ずしも(それが使用された方法に応じて)「壊れる」とは限りません。実際には、プログラムの動作を黙って変更する可能性があります。

それは心に留めておくべきことです。


1 少なくとも私が初めて知ったとき。


1
コンパイルしようとすると、とにかくコンパイラエラーが発生します。
ソンブレロチキン

@JameyD:どうする?2つの有効なコードシチュエーションで、意味が異なる結果がエラーになるのはなぜですか?
dhein

8
intCで「型が意味しない」に依存している場合、これから得られるすべての悪いものに値します。そして、それに依存していない場合、型一緒にautoストレージクラス指定子として使用すると、 C ++で素晴らしいコンパイルエラーが発生します(この場合、これは良いことです)。
AngewはSO

1
@Angewまあ、そうだね。そうだね。私はこれをしていません。しかし、それは少なくとも心に留めておくべきことです。
dhein

3

私が考えることができる1つの理由は、返されるクラスを強制する機会を失うことです。関数またはメソッドが64ビットのlongを返し、32のunsigned intだけが必要な場合、それを制御する機会を失います。


1
static_castがあり、たとえばIIRCはMeyersのEffective Modern C ++を使用して、自動型付き変数の型を指定することを推奨しています。
ハイド

2

この回答で 説明したように、auto意図しないファンキーな状況になることがあります。ポインタ型を作成できるauto&だけで、参照型があると明示的に言わなければなりませんauto。これにより、指定子がすべて省略されて混乱が生じ、実際の参照ではなく参照のコピーが作成される可能性があります。


2
ファンキーではありません。それが何をするかでautoあり、参照やconst型を推測することはありません。auto言及、あなたはより良い利用をいただきたいですauto&&。(汎用参照)型が安価にコピーできない、またはリソースを所有している場合、そもそも型はコピー可能であってはなりません。
Laurent LA RIZZA

1

別の苛立たしい例:

for (auto i = 0; i < s.size(); ++i)

は署名付き整数comparison between signed and unsigned integer expressions [-Wsign-compare]であるため、警告()を生成しますi。これを回避するには、たとえば、

for (auto i = 0U; i < s.size(); ++i)

またはおそらくより良い:

for (auto i = 0ULL; i < s.size(); ++i)

1
はい私もこれをイライラさせます。しかし、言語の穴はどこかにあります。このコードを本当に移植性のあるものにするにsizesize_t、戻り値を想定して、size_tのようなリテラルを持つ必要があり0zます。ただし、これを行うにはUDLを宣言できます。(size_t operator""_z(...)
Laurent LA RIZZA 2017年

1
純粋に理論的な異論:メインストリームアーキテクチャのunsignedすべての値を保持するのに十分なほど大きくない可能性が非常に高いため、非常に膨大std::size_tな数の要素を持つコンテナが誰かにあるというまれな場合、使用unsignedすると、低い範囲で無限ループが発生する可能性がありますインデックスの。これが問題になることはほとんどありませんが、std::size_t意図を適切に伝えるクリーンなコードを取得するために使用する必要があります。unsigned long long実際にはそれはおそらく同じであるに違いないが、それで十分であることが厳密に保証されているかどうかはわかりません。
underscore_d

@underscore_d:はい、公正なポイント- unsigned long long少なくとも64ビットであることが保証されていますが、理論的にsize_tはこれよりも大きくなる可能性があると思います。もちろん、コンテナーに2 ^ 64を超える要素がある場合、心配する必要のある大きな問題が発生する可能性があります... ;-)
Paul R

1

autoローカライズされたコンテキストで使用すると、読者がそのタイプを簡単かつ明らかに差し引くことができるか、実際のタイプを推測するそのタイプのコメントまたは名前で十分に文書化されていると、良いと思います。それがどのように機能するかを理解していない人は、代わりにtemplateまたは類似のものを使用するなど、間違った方法でそれをとるかもしれません。私の考えでは、いくつかの良いユースケースと悪いユースケースがあります。

void test (const int & a)
{
    // b is not const
    // b is not a reference

    auto b = a;

    // b type is decided by the compiler based on value of a
    // a is int
}

良い使い方

イテレータ

std::vector<boost::tuple<ClassWithLongName1,std::vector<ClassWithLongName2>,int> v();

..

std::vector<boost::tuple<ClassWithLongName1,std::vector<ClassWithLongName2>,int>::iterator it = v.begin();

// VS

auto vi = v.begin();

関数ポインタ

int test (ClassWithLongName1 a, ClassWithLongName2 b, int c)
{
    ..
}

..

int (*fp)(ClassWithLongName1, ClassWithLongName2, int) = test;

// VS

auto *f = test;

悪い使い方

データフロー

auto input = "";

..

auto output = test(input);

関数の署名

auto test (auto a, auto b, auto c)
{
    ..
}

些細なケース

for(auto i = 0; i < 100; i++)
{
    ..
}

が必要な場合はint、さらに1文字入力する必要がありますauto。それは受け入れられない
レリート2016年

@Reritoはい、それはintここで簡単に見られるもので、タイピングintはより短くなります。だから、それは些細なことです。
Khaled.K 2016年

0

誰もこれについて言及していないことに驚いていますが、何かの階乗を計算しているとします。

#include <iostream>
using namespace std;

int main() {
    auto n = 40;
    auto factorial = 1;

    for(int i = 1; i <=n; ++i)
    {
        factorial *= i;
    }

    cout << "Factorial of " << n << " = " << factorial <<endl;   
    cout << "Size of factorial: " << sizeof(factorial) << endl; 
    return 0;
}

このコードはこれを出力します:

Factorial of 40 = 0
Size of factorial: 4

それは明らかに期待される結果ではありませんでした。これautoは、変数階乗の型intがに割り当てられたためと推定されたために発生しました1

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.