世界を動かす技術を、日本語で。

Chromiumにおける禁止されたC++機能

概要

  • Chromium C++スタイルガイドの一部であり、近年のC++標準およびAbseilライブラリの新機能・更新機能のサポート状況をまとめた内容
  • Chromiumおよびサブプロジェクトに適用され、サブプロジェクトは必要に応じてより制限的な方針を採用可能
  • 新標準の機能は即時利用不可、ツールチェーン対応後に「初期サポート」段階を経て、議論後に許可・禁止が決定
  • 禁止機能やサードパーティコードの扱い、機能の許可・禁止提案の流れも明記
  • 各C++バージョン・Abseilの許可・禁止機能リストあり

Chromium C++ 標準機能・ライブラリ機能 サポート方針まとめ

  • C++標準 は3年ごとに更新、 Chromium は即時採用せず、 ツールチェーン対応 後に「初期サポート」宣言
  • 「初期サポート」状態では 新機能は原則禁止、議論を経て許可・禁止を決定
  • 機能の許可・禁止変更提案 はcxx@chromium.orgへメールで申請、議論合意後にファイルを修正
  • TBDリスト の項目は2年経過後に明示的に許可リストまたは禁止リストへ移動
  • サードパーティライブラリ は原則内部で禁止機能利用可能だが、 セキュリティやコンパイラサポート に問題ある場合は利用不可

C++標準・Abseilのサポート状況

  • C++11: デフォルト許可、ただし一部禁止機能あり
  • C++14: デフォルト許可
  • C++17: デフォルト許可、一部禁止機能あり
  • C++20: 2023年11月13日より初期サポート、許可・禁止・TBD機能あり
  • C++23: 2026年1月より初期サポート予定
  • C++26: 未サポート
  • Abseil: デフォルト許可、一部禁止・TBD機能あり

禁止機能およびサードパーティコードの扱い

  • サードパーティライブラリ は内部で禁止機能利用可能
  • ただし コンパイラサポート不十分 または セキュリティ問題 がある場合は利用不可
  • Chromiumコードがサードパーティの禁止型をインターフェースで利用する場合、 即座に許可型へ変換 が必要
  • セキュリティやコンパイラサポート理由で禁止されている場合は、 cxx@chromium.org と相談

C++11 禁止言語機能

  • インライン名前空間 (inline namespace): バージョン管理向け機能、Google Style Guideで禁止
  • long long型: 64ビット以上の整数型
  • ユーザー定義リテラル: 独自リテラル表現の定義

C++11 禁止ライブラリ機能

  • <cctype>, <ctype.h>, <cwctype>, <wctype.h>: ASCII文字ユーティリティ、Cロケール依存と未定義動作のため禁止、 absl/strings/ascii.h を代用
  • <cfenv>, <fenv.h>: 浮動小数点制御
  • <chrono>: 日付・時刻ライブラリ、base/timeと重複
  • <exception>: 例外処理
  • <random>のエンジン・ジェネレータ: 疑似乱数生成
  • <ratio>: コンパイル時有理数、Google Style Guideで禁止
  • <regex>: 正規表現、Chromium内の他ライブラリと重複、 third_party/re2 推奨
  • std::aligned_{storage,union}: アラインメント確保、C++23で非推奨、 alignas(T) char buf[sizeof(T)] を推奨
  • std::bind: 関数オブジェクト生成
  • std::function: 多態関数ラッパー
  • std::shared_ptr / std::weak_ptr: 共有・弱参照ポインタ、base::WeakPtrを推奨
  • *std::{sto,to_string}**: 文字列と数値変換、例外依存やパフォーマンス問題、 base/strings/string_number_conversions.h を推奨
  • スレッドサポートライブラリ: <barrier>, <condition_variable>, <future>, <latch>, <mutex>, <semaphore>, <stop_token>, <thread>、base/synchronizationと重複、base::Thread推奨

C++17 禁止言語機能

  • UTF-8文字リテラル (u8'X'等): char8_t禁止のため、未修飾リテラルを推奨

C++17 禁止ライブラリ機能

  • 数学特殊関数: std::assoc_laguerre等、多数
  • 並列アルゴリズム: std::execution::par等、libc++サポート不完全、Chromeのスケジューラ・スレッドAPI利用を推奨
  • std::aligned_alloc: アラインメント確保
  • std::any: 型安全な汎用コンテナ
  • std::byte: バイト表現
  • std::filesystem: ファイルシステム操作
  • std::{from,to}_chars: 文字列と数値変換、base/strings/string_number_conversions.hと重複
  • std::{pmr::memory_resource, polymorphic_allocator}: メモリリソース管理、PartitionAlloc利用のため不要
  • std::timespec_get: 時刻取得、base::TimeDelta::ToTimeSpec()利用推奨
  • std::uncaught_exceptions: 例外数取得、例外禁止のため
  • 透明なstd::owner_less: std::shared_ptr/weak_ptrが禁止のため
  • weak_from_this: std::shared_ptr/weak_ptrが禁止のため

機能の許可・禁止の議論と管理

  • 新機能の許可・禁止提案 はcxx@chromium.orgにメール送付
  • 機能の説明、許可・禁止理由、過去議論のリンクを添付
  • 合意形成後、 コードレビューでファイル修正、議論スレッドへのリンク必須
  • TBDリスト に2年以上残った場合、明示的に許可または禁止へ分類

推奨代替・注意事項

  • 文字列・数値変換: base/strings/string_number_conversions.h
  • ASCII文字ユーティリティ: absl/strings/ascii.h
  • 正規表現: third_party/re2
  • スレッド・同期: base/synchronization, base::Thread
  • 共有・弱参照ポインタ: base::WeakPtr

まとめ

  • Chromium C++開発 では、 標準機能の利用制限独自の推奨実装 を明確に定義
  • セキュリティ・移植性・パフォーマンス 重視の方針
  • 新機能利用には合意形成・明確な手続き が必要
  • サードパーティ・独自実装の活用標準ライブラリの取捨選択 が特徴

Hackerたちの意見

特に目立ったことはないかな。多くは「自社用に設計したものがあるから、標準ライブラリの代わりにそれを使ってね」って感じだね。残りは、ロケール地獄を避けるような、非常に合理的な内容だと思う。一部は標準ライブラリの粗を削るためのオプションっぽいけど、それも妥当だよね。

「私たちは自社用に設計したものがあるから、標準ライブラリの代わりにそれを使って。」 そうそう、古いコードベースの企業ではよくある話だよね。「chrono」を使わないで、私たちの独自の日付/時間型があるから。標準ライブラリのコンテナも使わないで、STLが安定する前からある独自のコンテナがあるから。今日、真っさらな.cppファイルから始めるプロジェクトにどれだけのこれら(またはGoogleスタイルガイドのルール)が意味を持つのか、ちょっと疑問だな。多分、あまりないだろうね。

注目すべきは、char8_tが禁止されている理由が非常に合理的で、ほとんどのコードベースに当てはまることだね。> 「charとプレフィックスなしの文字リテラルを使え。」Chromiumでは非UTF-8エンコーディングはかなり稀だから、型レベルで区別する価値が低いし、char8_tはcharと相互変換できない(Chromium、STL、プラットフォーム固有のAPIがほぼ全て使っているもの)から、u8プレフィックスを使うとあちこちにキャストを挿入しなきゃいけなくなる。データのブロックが文字列のようなもので、任意のバイナリの塊ではないと型レベルで宣言したいなら、char*よりもstd::string[_view]を使うのがいいよ。

Googleのことは詳しくないけど、私のちょっとロマンチックすぎる理解では、彼らは特定の技術について質問しないんだ。なぜなら、すべてに社内版があるから。問題は、あまりにも多くの人がその考えに飲まれて、全体像を理解せずにすべてをそのまま真似ようとしていることだね。一番の例はKubernetesかな。20人の開発者と50のサービスを持つ多くの組織で使われてる。

いろんなところで、stdの実装が何らかの面で自分たちのものより劣ってるって指摘されてるから、単に組織の慣性だけじゃなくて、C++の標準型は妥協なしでより良く設計できたはずなんだよね。

特に注目すべきことはないね。多くは「私たちのユースケースのために社内で設計したものがあるから、標準ライブラリの代わりにそれを使って」って感じ。制限の大半は「Googleスタイルガイドで禁止されている」と正当化されてる。結局、Googleスタイルガイドは、彼らがほとんどのレガシーコードをリファクタリングできない/しないから、多くの機能を禁止してるんだ。だから、これらのガイドラインは、Googleのほとんどメンテナンスされていないコードベースの上流と下流の利用者にとって安全を保つための反映に過ぎないんだよね。

例外は禁止だけど、Windowsには例外があるみたい。

"exception"と"Windows"でgrepしたけど、要するにWindowsに関する言及は[[no_unique_address]]だけみたい。だから、たぶんジョークを見逃してるかも :)

これをずっと持ち出してくる人たちは、Googleのコードが最初に例外安全ではないCスタイルで書かれていたってことをいつも見落としてるよね。要点は、「もし最初からやり直すことになったら、状況は多分違ってた」ってこと。例外を使うことの利点は、特に新しいプロジェクトではコストを上回るけど、既存のコードに例外を導入すると、依存しているコード全体に影響が出るんだ。新しいプロジェクトから例外が伝播する可能性があると、例外を使わない既存のコードに新しいプロジェクトを統合するのも問題になる。Googleの既存のC++コードは例外に対応してないから、例外を生成する新しいコードを採用するのは比較的難しいんだ。Googleの既存のコードが例外に耐えられないから、例外を使うコストは新しいプロジェクトのコストよりもやや高くなる。変換プロセスは遅くてエラーが起こりやすいしね。エラーコードやアサーションのような例外の代替手段が大きな負担をもたらすとは思ってないよ。例外を使わないことを勧めるのは哲学的や道徳的な理由じゃなくて、実用的な理由なんだ。Googleのオープンソースプロジェクトを使いたいけど、それらのプロジェクトが例外を使ってると難しいから、Googleのオープンソースプロジェクトでも例外を使わないようにアドバイスする必要があるんだ。もし最初からやり直すことになったら、状況は多分違ってたかもね。

モジュールは禁止されてるけど、Dのモジュールをそのままコピーすればよかったのに。

親ディレクトリにはもっと面白いドキュメントがあるよ :) https://chromium.googlesource.com/chromium/src/+/main/styleg...

禁止された機能の代替案はどこにリストされてるの?例えば、> 「テストのサポートが不十分で、内在するセキュリティ脆弱性があるヘッダー。」

たぶん、https://www.chromium.org/developersじゃないかな。そこには、そういう情報が必要な人たちのための情報が全部あるし。

base/files

禁止されたライブラリ機能のほとんどについては、代わりに使うべきものがメモに書いてあるよ。これは例外の一つだけどね。

禁止されたJavaの機能リスト(あるいは禁止されたC#の機能リスト)を見ることはほとんどないよね。一方で、真剣なC++開発チームは禁止された機能のリストを持っているものだよ。Javaは、禁止したい機能を排除したからね。

これ、事実として間違ってるし、歴史を無視してるね。Javaには使うべきじゃないものがたくさんあるよ。シリアライズ(今はJacksonを使うべき、組み込みのやつじゃなくて)、日付/時間(ゴミクラスを誤って使わないように全く別の名前空間がある)、とかね。C#も同様に、今は避けるべき古い欠点がある。 .NET Frameworkはその良い例だよ(今のC#とは全然違う、昔は「dotnet core」と呼ばれてた)。WPFやMAUIもそうだし。「dynamic」が型システムが進化する前の型の逃げ道として使われていた時期もあった。ASPがASP.NETと互換性がないとか、挙げたらキリがないよ。言語に過ぎないんだから、完璧だと装う理由なんてないよ。

Javaプログラマーとして思いつくのは一つだけだな:リフレクション。特別なことをする必要がない限り、普通のアプリケーションコードではほぼ確実に悪いアイデアだよ。それ以外は、特定のJVMバージョンに制限するか、ずっと前により良い選択肢に置き換えられた古い構文やパターンを使わないように人に言うことくらいだね。

禁止されたJavaの機能リストって、ほとんど見かけないよね… instanceof[0] 演算子は、アプリケーションコードでは使うのが一般的に禁止されていて、ライブラリの実装でもあまり好まれないことが多い。

Javaには、暗黙的に禁止される機能がたくさんあると思う。例えば、現代のコードベースでは java.util.Vector を見ることはまずないし、実際には誰も implements Serializable なんてやらないよね。 Objects.equals()Objects.hashCode() で、equals/hashコードの実装の99%は乗り切れるし。まだまだ続くけど、古い機能を使うのが「危険」だったり「理解しづらい」ってことはあまりない気がする。C++のリストとは違って。Javaは、より良いものに置き換えていくから、自然にその後ろに流れができるんだよね。

現代の言語でも、ほとんどのコードベースには禁止された機能のリストがあると思う。通常はリンターを使ってこれをキャッチするよね。

C#では、こういうルールをカスタムのRoslyn Analyzerや https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyze... で実装するのが普通だよ。C#プロジェクトは成熟したC++プロジェクトよりも禁止リストが小さい傾向があるけど、成熟したC#プロジェクトにも禁止されたAPIは確実に存在するね。

うちも、たくさんの会社がSonarや似たようなツールでスタイルガイドを強制してるけど、みんなそれをインターネットに公開してるわけじゃないよね。

Unityでゲームを開発してるなら、クラスやLINQみたいなC#の機能を禁止してるかもね(ヒープに割り当てるから、Unityのガベージコレクターが悪くて、ゲームが微フリーズしたりするから)。クラスが問題ないケースもあるけど(シングルトンやプーリングとか)、それでも...

ここで古いコードベースについてのコメントを見てたら、Chromiumが新しかった頃のことを思い出して、なんだか懐かしくなったよ。20年前にこのコードベースの開発を始めたことを思い出して、すごく年を取った気分になった!

あのu8"..."リテラルの指摘はいいね。ソースコードはすべてUTF-8で書かれるべきだから、引用符の間に直接UTF-8のテキストを書けるようにするべきだよ。まさにその理由だね。これらのリテラルは問題を探している解決策…実際に問題はあるけど、もっと良い解決策があるよ。

このリスト、C言語の機能よりも長い気がする。最初の印象としては、すごく圧倒されるね。

[禁止] 良い判断だと思う。昔一度使おうとしたけど、UTF-8にすらちゃんと対応できないことに気づいた。こんな欠陥のある設計がどうやって標準化されたのか、謎だよ。