-
Notifications
You must be signed in to change notification settings - Fork 157
Commit
ref: - cpprefjp/kunai#69 - #487
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,23 +9,29 @@ C++17では`bool`型に対する前置および後置の`operator ++`を削除 | |
|
||
具体的にどのような働きをするのかというと、以下のように値を`true`に書き換える機能をもつ。 | ||
|
||
```cpp | ||
```cpp example | ||
#include <iostream> | ||
int main() | ||
{ | ||
bool b = false; | ||
++b; // => true | ||
++b; // => true | ||
const b1 = ++b; | ||
std::cout << std::boolalpha << b1 << std::endl; // => true | ||
const b2 = ++b; | ||
std::cout << std::boolalpha << b1 << std::endl; // => true | ||
} | ||
``` | ||
|
||
ここで、前置の`operator ++`は、以下のように置き換えられる: | ||
|
||
```cpp | ||
```cpp example | ||
#include <iostream> | ||
int main() | ||
{ | ||
bool b = false; | ||
b = true; // => true | ||
b = true; // => true | ||
b = true; | ||
std::cout << std::boolalpha << b << std::endl; // => true | ||
b = true; | ||
std::cout << std::boolalpha << b << std::endl; // => true | ||
} | ||
``` | ||
|
||
|
@@ -79,9 +85,10 @@ C++17ではこれらが削除され、`opeartor ++`の定義(§ 8.2.6 expr.post. | |
|
||
この項は**十分な出典が存在せず推測でしかない**ことに注意して読み進めてほしい。 | ||
|
||
もともとC++の前身であるC言語(ANSI C89)には`bool`型は存在しなかった。そのために、真理値を`int`型で代用する例が見られた。 | ||
もともとC++の前身であるC言語(ANSI C89)には`bool`型は存在しなかった。 | ||
そのために、真理値を表すために`bool`型の代わりとして`int`型や`char`型、`unsigned char`型で代用する例が見られた。 | ||
|
||
```c | ||
```c example | ||
int main(void) | ||
{ | ||
int flag = 0; | ||
|
@@ -95,14 +102,17 @@ int main(void) | |
つまり、非0を`true`、0を`false`として扱う。ここで次のようなコードを見てみよう。 | ||
```cpp | ||
```cpp example | ||
#include <iostream> | ||
#include <vector> | ||
#include <limits> | ||
//説明の都合上using aliasではなくあえてtypedefを使用します | ||
typedef unsigned char my_bool; | ||
int main() | ||
{ | ||
std::vector<int> v{}; | ||
//append elements to v | ||
int flag = 0; | ||
std::vector<short> v(static_cast<std::size_t>(std::numeric_limits<my_bool>::max()) + 3); | ||
my_bool flag = 0; | ||
for(auto&& i : v){ | ||
if(flag++) std::cout << ','; | ||
std::cout << i << std::endl; | ||
|
@@ -111,7 +121,7 @@ int main() | |
``` | ||
|
||
これは、最初の要素以外のときは`,`という文字を要素の出力の前に行うことを期待している。しかし期待通りには動かない。 | ||
`flag`が`int`型の最大値になったときif文の条件評価が行われることを考えよう。`flag`のインクリメントはオーバーフローするので未定義動作になるが、殆どの環境で2の補数表現を使っているため、`int`型の最小値になる。すると、`flag`の値が再び0まで加算された際にカンマが出力されない。 | ||
`flag`が`unsigned char`型の最大値になったときif文の条件評価が行われることを考えよう。`flag`のインクリメントはオーバーフローするので未定義動作になるが、殆どの環境で2の補数表現を使っているため、`unsigned char`型の最小値になる。すると、`flag`の値が再び0まで加算された際にカンマが出力されない。 | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
yumetodo
Author
Member
|
||
|
||
これに起因するバグで少なくとも6つの過度の放射線被曝事故を引き起こし、3人が死亡した例がある。 | ||
Therac-25はカナダ原子力公社(AECL)とフランスCGR-MeV社によって開発・製造された放射線療法機器である。 | ||
|
1 comment
on commit fcf8708
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
めちゃくちゃ助かります
@yumetodo flag の型を int から unsigned char に変更したことで、
インクリメントによるオーバーフロー(およびその結果としての未定義動作)は
起こらなくなっているほか、2の補数表現も関係なくなっていて、
規格で保証される範囲の結果として最大値から 0 にラップするようになって
います。
ラップした時点で 0 なので、つづく「flagの値が再び0まで加算された際」
という記述もちょっと変になっちゃってます。
・・・現状のコードに即した文面に直していくことも考えられますが、
サンプルコードの実行はあんまり重要なものではないと思うので、めんどうなら
ここは元の状態に戻しちゃえばいいんじゃないかと思ってます。