{…} while(false)を実行


125

私は個人がいくつかのコードを見ていて、彼が彼の機能にパターンを持っているように見えることに気づきました:

<return-type> function(<params>)
{
 <initialization>

 do
 {
   <main code for function>
 }
 while(false);

 <tidy-up & return>
}

それは悪くはなく、より奇妙です(実際のコードはかなりきちんとしていて驚くことではありません)。それは私が以前に見たものではなく、誰かがその背後にあるロジックについて考えることができるかどうか疑問に思いました-おそらく別の言語の背景?


2
それを「通常の」バージョンに変更して、それでもコンパイルできるかどうか確認してみましたか?正常に書き込まれたときにコンパイルに失敗した場合、コンパイラエラーが原因でこれが行われた理由を知ることができます。
マークバイアーズ

11
彼の意図を推測するのではなく、「個人」に尋ねてみませんか?

1
たぶん彼の教授は彼にaを使うことdo...while()を要求し、それ以来彼はそのコードを関数テンプレートとして使ってきました。
ホーガン

6
@ニール...私が彼に立ち向かうとき、私は馬鹿に見えるのを避けたいと思います、そして彼は私が考えたこともない超高度なC ++の使い方を説明します。
氏Mr. Boy

6
すでにかなりの数の異なる回答があるようですが、元の作者に彼らの意図は何であるか尋ねてポストバックできますか?
nevets1219 2010

回答:


175

あなたはbreak外にすることができdo{...}while(false)ます。


95
+1はおそらくコードの目的ですが、このようなことをするのは、ばかげて偽装されたgotoです。あなたは後藤が仕事のための適切なツールであると考えられる場合は、その後、あなただけの#$(*#@後藤を使用する必要があります。
dsimcha

55
変装後藤以上のものです。制限された(構造化された)gotoです。
Thomas Eding、2010

19
どのように「制限」されていますか?前にジャンプするだけでは、ほとんど「制限」ではありません。後藤とは後藤のことで、そもそも後藤を使ってそれがそうではないように見せかけるのは、そもそも後藤を使用するよりも悪いことです。
アノン。

44
@Anon .:前方へのジャンプはgotoの制限であり、飛び出すことは間違いなく制限です。gotosの本当の問題はスパゲッティコードであり、それによってジャンプの前方と外側のジャンプが大幅に制限されます。
David Thornley、2010

33
実際のループは、意味的には後藤ではありません。条件文は意味的に後藤ではありません。「関数の最後に移動してクリーンアップコードを実行する」は、意味的にgotoです。セマンティクスが適用される場合はゴトを使用してください。怖いので、意味的に異なるものをドレスアップしないでください。
アノン。

126

多くの人が、「goto」を書くのに厄介な方法として、breakと一緒に使用されることが多いと指摘しています。関数に直接記述されている場合は、おそらくそれが当てはまります。

マクロでは、OTOH do { something; } while (false)は、マクロの呼び出し後にセミコロンを強制する便利な方法です。絶対に他のトークンを続けることはできません。

もう1つの可能性は、ループがあったか、反復が将来追加されることが予想されることです(たとえば、テスト駆動開発では、テストに合格するために反復は必要ありませんでしたが、論理的にはループする場合に意味があります)関数は、現在必要なものよりもいくぶん一般的である必要がありました)


18
マクロでこれの有用性について言及した場合は+1。他の誰もそれについて言及しなかったことに驚いています!
Nick Meyer

7
うん、マクロのことは実際にはこれの完全に有効な使用法です。もちろん、マクロの外では、それはばかげています...;)
jalf

12
スコープ付きの goto なので、扱いにくくなく便利です。つまり、doループで宣言した変数は破棄されますが、gotoは破棄しません。
Ana Betts

9
@Paul:gotoでこの動作を強制するために、一連のステートメントの前後に中括弧を追加することを妨げるものはありません。
erikkallen 2010

5
@Paul:ブロックから移動すると、C ++では、breakと同じようにローカル変数が破壊されます。Cの変数は実際には破壊されず、スタックスペースが再利用されます。
Ben Voigt

25

gotoとしての休憩はおそらく答えですが、私はもう1つのアイデアを提案します。

おそらく、彼はローカルに定義された変数を持ちたいと考え、この構成を使用して新しいスコープを取得しました。

最近のC ++では{...}どこでも可能ですが、これが常に当てはまるとは限りません。


30
その場合は、中括弧を使用することもできます。
Nemanja Trifunovic 2010

2
@Nemanja、多くの開発者がそれを知らず、ホーガンの提案に関連することを試してみることに驚くでしょう
Polaris878

8
@Polaris @Nemanja、新しいローカルスコープを{} どこにでも作成できることがわかったのは、4年ほどC / C ++でプログラミングしてからでした。これは、switch-caseコードで特に便利です
Earlz

1
@Nemanja:正確な時期はわかりませんが{...}、C ++ のどこかがよりモダンな開発であると確信しています(私が使用した最初のC ++はプリプロセッサで実装されていたため、このモダンな使用はできませんでした)。著者はまさに古い学校でした。
ホーガン

2
どこでもブレースが許可されなかったのはいつですか?私は15年前のようにプログラミングを始めましたが、それが許可されました(私の教科書でも、私が試したすべてのコンパイラでも)。
erikkallen 2010

20

これは、関数の潜在的な出口点が多数ある場合に有用なパターンとして使用されることを確認しましたが、関数の終了方法に関係なく、常に同じクリーンアップコードが必要です。

終了ポイントに到達するたびにブレークし、残りのロジックを後でインライン化する必要があるため、if / else-ifツリーを非常に読みやすくすることができます。

このパターンは、gotoステートメントがない言語でも役立ちます。おそらくそれが、元のプログラマーがパターンを学んだ場所です。


15
次に、薄く偽装した後藤ではなく、正直でわかりやすい後藤を使用します。
dsimcha

4
私はこの方法が好きです。読みやすく、後藤の汚名もありません。
Cameron

8
gotoは、ローカルで控えめに使用すると、完全に読みやすくなります。彼らはフロー制御の主な形態であり、何百ものラインを飛び越えていたとき、彼らは後ろから彼らの汚名を得ました。
dsimcha

13
「スティグマ」のためにgotoを使用しないことは、カーゴカルトプログラミングの確かな兆候です。
アノン。

6
クリーンアップコードの大部分は悪臭であることは言うまでもありません。これはC ++であり、クリーンアップコードは通常、RAII処理中に呼び出されるデストラクタにある必要があります。
David Thornley、2010


10

これはwhile、セマティックスを取得するための単なる変態ですgoto tidy-up、gotoという単語を使用せずに。

あなたが使用している場合ので、それは悪いフォームの他の外側の内側のループを読者に曖昧になります。 「これは出口に行くことになっていますか?これは内部ループから抜け出すことのみを目的としていますか?」whilebreaks


10

break代わりに書く方が便利だと思いますgoto end。意図を明確にするラベルの名前を考える必要もありません。特定の名前のラベルにジャンプする必要はありません。あなたはここから抜け出したいのです。

また、とにかく中かっこが必要になる可能性もあります。これがdo{...}while(false);バージョンです:

do {
   // code
   if (condition) break; // or continue
   // more code
} while(false);

そしてこれはあなたが使いたいならあなたがそれを表現しなければならない方法ですgoto

{
   // code
   if (condition) goto end;
   // more code
}
end:

最初のバージョンの意味はずっと理解しやすいと思います。また、記述しやすく、拡張しやすく、サポートしていない言語に翻訳しやすくなりますgoto


の使用に関して最も頻繁に言及される懸念breakは、それがひどく偽装されていることgotoです。しかし、実際にbreakはより類似していreturnます:両方の命令は、と比較してかなり構造化されたコードのブロックから飛び出しgotoます。それでも、どちらの命令でも、コードのブロックで複数の出口点が許可されるため、混乱を招く場合があります。結局のところ、特定の状況にあるものは何でも、最も明確な解決策を模索するように努めるでしょう。


ああ、答える前に質問を完全に理解していないことに気づきました。do{ ... }while(false);一般的な使い方についてだと思いました。しかし、実際には、ある種のをエミュレートするためにそれを使用することですtry{ ... }finally{ ... }
Robert

gotoではなく、breakとreturnの類似点をよく観察します。最も明確なソリューションが最善であることに同意します。多くの場合、このようなコードを、ブレークではなくreturnを使用する独自の独立した関数にカプセル化し、呼び出し側の関数でクリーンアップを行う方がおそらく明確です。
永続化

7

このトリックは、恥ずかしがり屋でgotoコードで明示的に使用できないプログラマーによって使用されます。上記のコードの作成者は、コードの中央から「クリーンアップして戻る」ポイントに直接ジャンプする機能を必要としていました。しかし、彼らはラベルとエクスプリシットを使いたくありませんでしたgoto。代わりに、break上記の「フェイク」サイクルの本体の内部を使用して同じ効果を達成できます。


7

これは非常に一般的な方法です。ではC。私はあなたが「私は使っていない」のように自分嘘をつくことを望んでいるかのようにそれを考えようとしますgoto。考えてみれば、goto中古同様です。実際には、インデントレベルも低下します。

とはいえ、このdo..whileループは非常に頻繁に大きくなる傾向にあります。そして、それらはifsとelsesを内部に取り込み、コードを実際には非常に読みにくくし、さらにはテスト可能にします。

これらdo..whileは通常、クリーンアップを行うためのものです。可能な限り、RAIIを使用して、短い関数から早期に戻ることをお勧めします。一方、Cは、として、あなたは非常に便利として提供されていませんC ++がない作り、最高の一つは、クリーンアップを行うに近づきます。do..while


6

Cプログラマのように見えます。C ++では、自動変数にクリーンアップに使用するデストラクタがあるため、戻る前に片付ける必要はありません。Cでは、このRAIIイディオムがなかったので、一般的なクリーンアップコードがある場合は、goto、それを使用する、上記のように1回限りのループを使用します。

C ++のイディオムと比較した主な欠点は、本体で例外がスローされても片付けられないことです。Cには例外がなかったため、これは問題ではありませんでしたが、C ++では悪い習慣になっています。


4

いくつかの説明。1つ目は一般的なもの、2つ目はパラメータ付きのCプリプロセッサマクロに固有のものです。

フロー制御

これがプレーンなCコードで使用されているのを見てきました。基本的に、それはgotoのより安全なバージョンです。それを抜け出すことができ、すべてのメモリが適切にクリーンアップされるからです。

なぜ何かgotoが良いのでしょうか?ええと、ほとんどすべての行がエラーを返す可能性があるコードがあるが、それらすべてに同じように対応する必要がある場合(たとえば、クリーンアップ後に呼び出し元にエラーを渡すことにより)、通常は、より読みやすく、if( error ) { /* cleanup and error string generation and return here */ } asます。クリーンアップコードの重複を回避します。

ただし、C ++では、この目的に例外+ RAIIがあるため、コーディングスタイルが悪いと考えます。

セミコロンチェック

関数のようなマクロ呼び出しの後にセミコロンを忘れると、引数が望ましくない方法で縮小され、有効な構文にコンパイルされる可能性があります。マクロを想像してください

#define PRINT_IF_DEBUGMODE_ON(msg) if( gDebugModeOn ) printf("foo");

それは誤って

if( foo )
    PRINT_IF_DEBUGMODE_ON("Hullo\n")
else
    doSomethingElse();

「他」に関連しているとみなされるgDebugModeOnのでとき、fooありますfalse正確などうなることを意図したものとは逆の、。

一時変数のスコープを提供します。

do / whileには中括弧があるため、一時変数には、エスケープできない明確に定義されたスコープがあります。

「おそらく不要なセミコロン」警告の回避

一部のマクロは、デバッグビルドでのみアクティブになります。次のように定義します。

#if DEBUG
#define DBG_PRINT_NUM(n) printf("%d\n",n);
#else
#define DBG_PRINT_NUM(n) 
#endif

これを条件付きのリリースビルドで使用すると、コンパイルされます

if( foo )
    ;

多くのコンパイラはこれを

if( foo );

誤って書かれることが多い。したがって、警告が表示されます。do {} while(false)はこれをコンパイラーから隠し、本当にそれを示すものとして受け入れられますここで何もしないようにしたいです。

条件文による行のキャプチャを回避する

前の例のマクロ:

if( foo )
    DBG_PRINT_NUM(42)
doSomething();

デバッグビルドでは、セミコロンも常用しているので、これで問題なくコンパイルできます。ただし、リリースビルドでは、これは突然次のようになります。

if( foo )

doSomething();

またはより明確にフォーマット

if( foo )
    doSomething();

これは意図されたものとはまったく異なります。マクロの周りにdo {...} while(false)を追加すると、欠落しているセミコロンがコンパイルエラーになります。

OPとはどういう意味ですか?

一般に、エラー処理にはC ++の例外を使用し、マクロの代わりにテンプレートを使用します。ただし、まだマクロが必要である(トークン貼り付けを使用してクラス名を生成する場合など)非常にまれなケースや、プレーンCに制限されている場合、これは便利なパターンです。


スコーピングに関しては、ループ装置は必要ありません。「飾られていない」ブロックは合法ですx =1; y = 2; { int tmp = y; y = x; x = tmp; }
chepner 2017

装飾されていないブロックは、セミコロンの欠落を強制しませんが、望ましくない副作用が発生する可能性があります。一方を行います(); セミコロンが必要です。たとえば、上記の例のように、リリースビルドでマクロが何も定義されていない場合、後続のステートメントは「if」に描画されません。
公証人2017

マクロをより適切に定義することで、それを回避することはできませんか?#define DBG_PRINT_NUM(n) {}
chepner 2017

1
いいえ、{}は完全なステートメントであるため、つまり「;」と同等です。だから書いif(a) DBG_PRINT_NUM(n); else other();てもコンパイルされません。if(a) {} else other();or のみif(a) ; else other();が有効ですが、有効でif(a) {}; else other();はありません。これは、「if」句が2つのステートメントで構成されるためです。
公証人2017

2

多分それはbreak内部で使用され、任意の時点でさらなるコードの実行を中止するために使用されます:

do {
    if (!condition1) break;
    some_code;
    if (!condition2) break;
    some_further_code;
    // …
} while(false);

7
そうすることはgoto、誰かが「悪い」と聞いたからといって使用を回避しようとする試みのようです。
アノン。

1
おそらく、しかしC ++には、まさにこの理由で例外があります。
TED


2

それは簡単です。どうやら、breakステートメントを使用すると、いつでも偽のループから抜け出すことができます。さらに、doブロックは別のスコープです(これは、{ ... }のみで実現することもできます)。

そのような状況では、RAII(オブジェクトは、関数が終了すると自動的に正しく破壊される)を使用する方が良いでしょう。別の同様の構成はgoto- の使用です- はい、私はそれが悪であることを知っていますが、次のような一般的なクリーンアップコードを使用することができます:

<return-type> function(<params>)
{
 <initialization>

 <main code for function using "goto error;" if something goes wrong>

 <tidy-up in success case & return>

 error:

 <commmon tidy-up actions for error case & return error code or throw exception>
}

(余談ですが、do-while-falseコンストラクトはLuaで不足しているcontinueステートメントに対処するために使用されています。)


2

多くの回答者がの理由を述べましたdo{(...)break;}while(false)。さらにもう1つの実際の例でこの図を補足したいと思います。

次のコードではoperationdataポインターが指すアドレスに基づいて列挙子を設定する必要がありました。スイッチケースはスカラー型でのみ使用できるため、最初はこの方法で非効率的にしました

if (data == &array[o1])
    operation = O1;
else if (data == &array[o2])
    operation = O2;
else if (data == &array[on])
    operation = ON;

Log("operation:",operation);

しかし、Log()と残りのコードは、選択された操作の値に対して繰り返されるため、アドレスが既に検出されている場合、残りの比較をスキップする方法を探していました。そして、これがdo{(...)break;}while(false)重宝するところです。

do {
    if (data == &array[o1]) {
        operation = O1;
        break;
    }
    if (data == &array[o2]) {
        operation = O2;
        break;
    }
    if (data == &array[on]) {
        operation = ON;
        break;
    }
} while (false);

Log("operation:",operation);

彼は同じことを行うことができなかった理由の一つは、不思議に思うかもしれbreakifの文のように、:

if (data == &array[o1])
{
    operation = O1;
    break;
}
else if (...)

break単に最も近い囲むと相互作用ループ、それがあるかどうかまたはスイッチ、forwhileまたはdo .. whileタイプなので、残念ながらそれは動作しません。


1

著者は何歳でしたか?

80年代後半に、それを実行するリアルタイムのFortranコードに出くわしたことがあるので、質問します。それはそれらを持たないOSでスレッドをシミュレートするための本当に良い方法であることがわかりました。プログラム全体(スケジューラ)をループに入れ、「スレッド」ルーチンを1つずつ呼び出します。スレッドルーチン自体はループであり、いくつかの条件のいずれかが発生するまで繰り返されます(多くの場合、一定量の時間が経過しました。CPUを時々放棄するのは個々のスレッド次第なので、他のスレッドが枯渇しないようにする「協調マルチタスク」です。ループサブプログラム呼び出しをネストして、スレッドの優先順位をシミュレートできます。バンド。



0

私は薄く偽装した後藤としての使用法についてほとんどのポスターに同意します。マクロは、スタイルでコードを記述する潜在的な動機としても言及されています。

また、C / C ++の混在環境で使用されているこの構成体を、貧しい人の例外として見ました。「ブレーク」を伴う「do {} while(false)」を使用すると、ループで通常例外が発生することが保証されるはずのコードブロックの最後までスキップできます。

私はまた、「機能ごとの単一のリターン」のイデオロギーが実施されているショップで使用されているこの構成を使用しています。繰り返しますが、これは明示的な「goto」の代わりですが、動機は、コードを「スキップ」してその関数内で実際の実行を継続するのではなく、複数の戻り点を回避することです。


0

私はAdobe InDesign SDKを使用しており、InDesign SDKの例では、ほぼすべての関数がこのように記述されています。これは、通常、関数が本当に長いためです。アプリケーションオブジェクトモデルから何かを取得するためにQueryInterface(...)を実行する必要がある場合。したがって、通常、すべてのQueryInterfaceの後にifはうまくいきませんでした。


0

このコンストラクトとの類似性についてはすでに多くの人が述べておりgoto、gotoへの選好を表明しています。おそらく、この人物の背景には、コーディングガイドラインによってgotoが厳密に禁止されている環境が含まれていましたか?


0

私が考えることができるもう一つの理由はそれが飾ることです、中括弧をする、新しいC ++標準の裸の中括弧は大丈夫ではないと思います(ISO Cはそれらが好きではありません)。それ以外の場合は、lintのような静的アナライザーを停止します。

なぜそれらが必要なのか、おそらく変数スコープなのか、デバッガーの利点があるのか​​わかりません。

参照トリビアルdoループしながら、そして中括弧は良いです C2から。

私の用語を明確にするには(標準的な使用法に従っていると思います):

裸のブレース

init();
...
{
c = NULL;
mkwidget(&c);
finishwidget(&c);
}
shutdown();

空のブレース(NOP):

{}

例えば

while (1)
   {}  /* Do nothing, endless loop */

ブロック

if (finished)
{
     closewindows(&windows);
     freememory(&cache);
}

なるだろう

if (finished)
     closewindows(&windows);
freememory(&cache);

中括弧を削除すると、ローカル変数のスコープだけでなく、実行のフローが変更されます。したがって、「自立」または「裸」ではありません。

裸の括弧またはブロックは、マークしたい(インライン)関数の可能性があるコードのセクションを示すために使用できますが、その時点ではリファクタリングしません。


本当に?残念です。Cについて私が気に入った数少ない点の1つは、それによって、どこでも新しいネストされたスコープを宣言できることでした。
TED

1
裸のブレースは、奇妙なクラッシュを修正するのに役立つことがあります。blogs.msdn.com/oldnewthing/archive/2004/05/20/135841.aspxを参照してください。
ブライアン

1
C ++では、ブロック(つまり、「裸の括弧」)は、単一のステートメントが許可される場所ならどこでも使用できます。
ベンフォークト

@BenVoigt空の括弧、つまりNOPは、命令の線形シーケンスの周囲に追加されるブロックである「裸の括弧」とは異なります。たとえば、 `printf(" Hello "); {putchar( '、'); putchar(0x20); } printf( "world!\ n"); `中括弧はループまたは分岐制御の一部ではありません
mctylr

@mctylr:私は空のブレースについて話していませんでした。
Ben Voigt、2012年

0

GOTOこれら2つは実質的に同一であるため、をエミュレートするための工夫された方法です。

// NOTE: This is discouraged!
do {
    if (someCondition) break;
    // some code be here
} while (false);
// more code be here

そして:

// NOTE: This is discouraged, too!
if (someCondition) goto marker;
// some code be here
marker:
// more code be here

一方、これらはどちらも実際にはifs で実行する必要があります。

if (!someCondition) {
    // some code be here
}
// more code be here

ただし、フォワードGOTOの長い文字列をネストされたifsに変換すると、ネストが少し見苦しくなります。本当の答えは適切なリファクタリングですが、古い言語の構成要素を模倣していません。

GOTOsを含むアルゴリズムを必死に文字変換しようとした場合、おそらくこのイディオムでそれを行うことができます。それは確かに非標準であり、言語の予想されるイディオムに厳密に従っていないことを示す良い指標です。

実際、do / whileが何かのための慣用的な解決策であるCのような言語を私は知りません。

混乱全体をより理にかなった何かにリファクタリングして、より慣用的で読みやすいものにすることができます。


1
Alanは、「未定義」の回数を実行するためのものでdo..while(false)なく1回実行するためのものです。
ドミトリー

2
continue私が示したように、最後に条件ステートメントがある場合、それは未定義の回数実行されます。ことでundefined、私だけであなたは条件が特定の繰り返しで満たされるかどうかを予測することができない限り、それが複数回実行しているかどうかわからないということを意味します。どんなずにcontinueその中の、do..while(false)一度だけ実行されますが、また、いかなるせずにbreakその中の、while(true)「デフォルトの動作は」何を理解することは、実際には関係ありませんので、永遠に実行されますすることができ、ループを使って行うこと。
アランプラム

複数のステートメントを持つマクロを定義する場合に役立ちます。それらをdo / while(false)でラップすると、他の関数呼び出しと同様に、if / elseステートメントでマクロを使用できます。説明については、novelltheory.com / TechPapers / while.htmを参照してください
John Paquin

5
誰かがのセマンティクスを理解していませんcontinuecontinueループを繰り返しません。「continueステートメントは反復ステートメントでのみ発生し、制御は最小の囲み反復ステートメントのループ継続部分、つまりループの終わりに渡されます。」
ベンフォークト

-1、@ BenVoigtが指摘する理由により、上位2つのステートメントは同一ではありません。
cmh 2013

0

一部のコーダーは、関数からの出口/戻りを1つだけにすることを好みます。ダミーの使用は{....} while(false); 完了したらダミーループを「抜け出し」、単一の戻り値を得ることができます。

私はJavaコーダーなので、私の例は次のようになります

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class p45
{
    static List<String> cakeNames = Arrays.asList("schwarzwald torte", "princess", "icecream");
    static Set<Integer> forbidden = Stream.of(0, 2).collect(Collectors.toSet());

    public static  void main(String[] argv)
    {
        for (int i = 0; i < 4; i++)
        {
            System.out.println(String.format("cake(%d)=\"%s\"", i, describeCake(i)));
        }
    }


    static String describeCake(int typeOfCake)
    {
        String result = "unknown";
        do {
            // ensure type of cake is valid
            if (typeOfCake < 0 || typeOfCake >= cakeNames.size()) break;

            if (forbidden.contains(typeOfCake)) {
                result = "not for you!!";
                break;
            }

            result = cakeNames.get(typeOfCake);
        } while (false);
        return result;
    }
}


-1

これは面白いです。他の人が言っているように、ループの内側におそらくブレークがあります。私はそれをこのようにしたでしょう:

while(true)
{
   <main code for function>
   break; // at the end.
}

2
永遠にループする可能性がありますか?do..while(false)常に存在し、while(true)より危険な側面にあります。
ドミトリー

1
while(true)ほとんどの言語で正しいイディオムです。GUIアプリケーションでは、プログラムのメインループとしてよく見かけます。基本的に、プログラムは死ぬように言われるまで死ぬべきではないと想定しているので、はdo..while(false)あらゆる種類の不自然なロジックを引き起こします。このアプローチは完全主義のPOVからより危険かもしれませんが、意味的には簡単であり、したがって人間のプログラマー(申し訳ありませんが、スカイネット)のエラーが発生しにくくなっています。
アランプラム

2
@dmitry do{...}while(false)while(true){ .. break;}
N 1.1

4
@ N1.1:が存在しcontinueない場合、それらは同じではありません。
ベンフォークト
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.