C++は、手動メモリ管理を備えたマルチパラダイムプログラミング言語であり、手続き型、オブジェクト指向、ジェネリックプログラミングを組み合わせています。モバイル開発では、C++はAndroid NDKを介したライブラリのポーティングや、UnityやUnreal Engineゲームエンジンを介したクロスプラットフォームゲームの作成に使用されます。TIOBE (2026)によると、C++はプロフェッショナル開発者の間でトップ5の最も人気のある言語の一つです。
重要ポイント
C++は、1985年にビャーネ・ストロヴストルップによってC言語の拡張としてクラスサポートを備えて作成されたプログラミング言語です。C++は、ポインタによる直接メモリアクセス、テンプレートメタプログラミング、多重継承を提供します。C++17およびC++20標準では、コルーチン、コンセプト、レンジが追加されました。
JavaやKotlinとは異なり、C++にはガベージコレクタがありません — 開発者はnew演算子とdelete演算子を使って手動でメモリの割り当てと解放を管理します。これによりパフォーマンスを完全に制御できますが、規律が必要です。JetBrains Developer Survey (2025)によると、C++開発者の42%がゲーム業界でこの言語を使用しています。
C++標準は3年ごとに進化しています: C++11 (ラムダ、auto、unique_ptr)、C++14 (ジェネリックラムダ)、C++17 (if constexpr、filesystem)、C++20 (モジュール、コルーチン、コンセプト)。ClangおよびGCCコンパイラはすべての最新標準をサポートしており、Android NDKはLLVMツールチェーンからClangを使用しています。
C++とJVM言語の主な違いは、手動メモリ管理とマシンコードへの直接コンパイルです。JavaとKotlinは自動ガベージコレクションを備えた仮想マシン上で動作します。C++コードは、ARM、x86、RISC-Vなどの特定のアーキテクチャ向けのネイティブバイナリにコンパイルされます。
| 基準 | C++ | Java / Kotlin |
|---|---|---|
| メモリ管理 | 手動 (new/delete、RAII) | 自動 (ガベージコレクタ) |
| コンパイル | ネイティブマシンコード | JVM / ART バイトコード |
| パフォーマンス | 最大 (ゼロコスト抽象化) | 高い(GC停止あり) |
| モバイル開発での使用 | NDK、ゲーム、ライブラリ | UIアプリ、ビジネスロジック |
| ビルド | CMake、NDK Build、Gradle + NDK | Gradle、Maven |
| クロスプラットフォーム | 各プラットフォーム向けにコンパイル | どこでもJVM / ART |
Android NDK (Native Development Kit)は、Androidアプリケーションの一部をCやC++で記述するためのGoogleのツールキットです。NDKには、Clangベースのツールチェーン、Androidシステムヘッダファイル、デバッグおよびプロファイリングライブラリが含まれています。バージョンr27 (2025)はC++20をサポートし、LLVM 18を使用しています。
NDKは、C++コードをARM64、ARM32、x86、x86_64アーキテクチャ向けの動的.soライブラリにコンパイルします。JavaまたはKotlinアプリケーションは、System.loadLibrary()を介してこれらのライブラリをロードし、JNIを介してネイティブ関数を呼び出します。Googleによると、NDKは500万回以上ダウンロードされています。
典型的なAndroid NDKプロジェクトには、C++ソースファイルを含むapp/src/main/cpp/フォルダ、ビルド用のCMakeLists.txt、ネイティブメソッドを宣言するJavaクラスが含まれます。Gradleは、build.gradleのexternalNativeBuildブロックを介してNDKを接続します。
// native-lib.cpp — Android用のシンプルなJNIメソッド
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_app_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /*thiz*/) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}このコードは、Java_com_example_app_MainActivity_stringFromJNIという完全な名前でJNI関数を宣言しています — これがJNIの命名規則です。関数は、JNIEnv(実行環境)とjobject(呼び出し元クラスインスタンス)へのポインタを受け取ります。env->NewStringUTFは、C++文字列からJava文字列を作成します。
Androidは複数のABI(アプリケーションバイナリインターフェース)をサポートしています: arm64-v8a(64ビットARMデバイス、最新スマートフォンの99%)、armeabi-v7a(32ビットARM、レガシーデバイス)、x86_64(エミュレータ)。NDKは、build.gradleのABIフィルタを介して各アーキテクチャ向けに.soをビルドできます。
android {
defaultConfig {
ndk {
abiFilters "arm64-v8a", "armeabi-v7a"
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.22.1"
}
}
}C++はゲームエンジンの主要言語です。Unreal EngineはすべてのゲームコードにC++を使用し、Unityはレンダリングと物理演算にエンジンコアでC++を使用しています。開発者がUnityでC#で記述していても、内部ではC++がグラフィックス、サウンド、物理計算を管理しています。
Unreal EngineはゼロからC++上に構築されています。ゲームロジックコードは、ブループリント(ビジュアルスクリプティングシステム)との統合のためにUHT(Unreal Header Tool)マクロを使用してC++で記述されます。クラスは、プレフィックス文字U、A、Fを付けて基本型AActor、UObject、UGameInstanceから継承します。
// Unreal EngineでC++を使用したキャラクタークラス
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyCharacter.generated.h"
UCLASS()
class AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
AMyCharacter();
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
UPROPERTY(EditAnywhere, Category = "Movement")
float MoveSpeed = 600.0f;
protected:
void SetupPlayerInputComponent(UInputComponent *PlayerInputComponent) override;
};UCLASS()およびUPROPERTY()マクロは、Unreal Engineのリフレクションシステムの一部です。UHT(Unreal Header Tool)は、シリアル化、ブループリント、ネットワークレプリケーションのためにヘッダファイルからC++コードを生成します。MoveSpeedは、UPROPERTY(EditAnywhere)を介してエディタに表示されます。
UnityはゲームロジックにC#を使用しますが、C++はネイティブプラグイン(Android用の.soライブラリ、iOS用の.bundle)で使用されます。Android NDKを介して、広告ネットワークや分析のC++ SDKを統合したり、デスクトップゲームからC++ライブラリをポーティングしたりできます。
using System.Runtime.InteropServices;
using UnityEngine;
public class NativeBridge : MonoBehaviour
{
const string LIB_NAME = "native_plugin";
[DllImport(LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
private static extern int ProcessFrame(
int width, int height,
IntPtr pixelData
);
void Update()
{
int result = ProcessFrame(Screen.width, Screen.height, IntPtr.Zero);
Debug.Log("Frame processed: " + result);
}
}この例では、C#がP/Invokeを介してC++関数ProcessFrameへの呼び出しをマーシャリングしています。DllImport属性は.soライブラリの名前を指定します。C++関数はリアルタイムでフレームを処理し、結果を返します。このアプローチは、ポストエフェクトやコンピュータビジョンに使用されます。
JNI (Java Native Interface)は、JavaまたはKotlinからC/C++コードを呼び出すための標準メカニズムです。Androidでは、JNIがART仮想マシンとネイティブライブラリの間でデータを転送する唯一の方法です。各JNI呼び出しにはオーバーヘッドがあるため、データは一度に1フィールドずつではなく、バッチで転送する必要があります。
JNIEnvはJNI関数テーブルへのポインタです。env->FindClassはJavaクラスをロードし、env->GetMethodIDはメソッド識別子を取得し、env->CallVoidMethodはそれを呼び出します。文字列にはGetStringUTFCharsとReleaseStringUTFCharsを使用します。JNIは、Javaオブジェクトへのグローバル参照とウィーク参照もサポートしています。
// JNIを介してC++からJavaにバイト配列を渡す
extern "C" JNIEXPORT void JNICALL
Java_com_example_app_ImageProcessor_processArray(
JNIEnv *env, jobject /*thiz*/,
jbyteArray input, jint length) {
jbyte *buffer = env->GetByteArrayElements(input, nullptr);
jsize size = env->GetArrayLength(input);
for (jsize i = 0; i < size; ++i) {
buffer[i] = buffer[i] ^ 0xFF; // バイトを反転
}
env->ReleaseByteArrayElements(input, buffer, JNI_COMMIT);
}GetByteArrayElementsはJavaバイト配列へのポインタを取得します。ReleaseByteArrayElementsのJNI_COMMITは、メモリを解放せずに変更をJava配列にコピーして戻します。forループ処理は、GC停止なしで最大のC++パフォーマンスでCPU上で実行されます。
JNIの主な危険性は、グローバル参照のリークです。すべてのNewGlobalRefはDeleteGlobalRefを介して解放する必要があります。ローカル参照(FindClass、NewStringUTFが返すもの)は、ネイティブ関数から戻るときに自動的に解放されます。集中的な呼び出しには、PushLocalFrame / PopLocalFrameを使用してください。
CMakeは、Android NDKにおけるC++の主要ビルドツールです。CMakeLists.txtは、ビルドターゲット、ライブラリ、依存関係を記述します。Gradleは、externalNativeBuildを介してCMakeを呼び出し、NDKとツールチェーンへのパスを渡します。代替として、Android.mkとApplication.mkに基づくNDK Buildがあります。
CMake 3.22+は、異なる最適化フラグを持つデバッグ、リリース、プロファイルなど、さまざまな構成のプリセット(CMakePresets.json)をサポートしています。Androidでは、NDKのandroid.toolchain.cmakeツールチェーンが使用され、ビルド中にGradleによって自動的に提供されます。
# Android NDKプロジェクト用のCMakeLists.txt
cmake_minimum_required(VERSION 3.22)
project("native-lib")
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp
src/main/cpp/image_utils.cpp
)
target_include_directories(
native-lib PRIVATE
src/main/cpp/include
)
target_link_libraries(
native-lib
android
log
${CMAKE_SOURCE_DIR}/libs/libjpeg.a
)
set_target_properties(
native-lib PROPERTIES
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON
)add_library(SHARED)は.soライブラリを作成します。target_link_librariesは、システムライブラリのandroid(JNI用)とlog(__android_log_print用)をリンクします。静的ライブラリlibjpeg.aはJPEG画像処理用にリンクされます。CXX_STANDARD 20はC++20サポートを有効にします。
vcpkgは、Android NDKをターゲットプラットフォームとしてサポートするMicrosoftのC++パッケージマネージャです。vcpkgを介して、Android ABI用にコンパイルされたBoost、OpenCV、SQLite、nlohmann-jsonなどのライブラリをインストールできます。Vcpkgは、CMAKE_TOOLCHAIN_FILEを介してCMakeと統合します。
C++は、ネイティブARMコードへのコンパイルとガベージコレクタの不在により、モバイルデバイスで最大のパフォーマンスを提供します。Googleのテスト(Android Performance Patterns、2024)によると、計算集約型タスクにおいて、C++のJNIコードは同等のJavaコードより3〜10倍高速に実行されます。
モバイルプラットフォームにおけるC++パフォーマンスの主要因: キャッシュローカリティ(連続メモリレイアウト)、ARM向けNEON SIMD命令、メッセージキューを介した非同期JNI通信。NEONはARMのSIMD拡張であり、1命令で128ビットのデータを処理し、オーディオ、ビデオ、画像処理に不可欠です。
// NEON組み込み関数によるSIMD配列処理
#include <arm_neon.h>
void process_audio_neon(float *data, size_t n) {
for (size_t i = 0; i < n; i += 4) {
float32x4_t vec = vld1q_f32(&data[i]);
float32x4_t result = vmulq_f32(vec, vdupq_n_f32(0.5f));
vst1q_f32(&data[i], result);
}
}vld1q_f32はメモリから128ビットNEONレジスタに4つのfloatをロードします。vmulq_f32は1サイクルですべての4要素を0.5で乗算します。vst1q_f32は結果をストアします。SIMDがない場合、同じループは4回の乗算を逐次的に実行します — NEONはそのような操作で最大4倍の高速化を実現します。
| 操作 | C++ (ms) | Java/Kotlin (ms) | 高速化 |
|---|---|---|---|
| 1920x1080画像処理 | 12 | 45 | 3.75x |
| 高速フーリエ変換 (FFT) | 8 | 34 | 4.25x |
| 1MBブロックのAES-256暗号化 | 3 | 18 | 6x |
| ZLIBデータ圧縮 | 5 | 22 | 4.4x |
最初で最も危険な間違いはメモリリークです。すべてのnewにはdeleteが、すべてのnew[]にはdelete[]が必要です。RAMが限られているモバイルデバイスでは、リークが発生するとOOM(メモリ不足)とアプリクラッシュにつながります。スマートポインタ(std::unique_ptr、std::shared_ptr、std::weak_ptr)を介してRAIIを使用してください。
2つ目の間違いはABI互換性の無視です。armeabi-v7a用にコンパイルされたライブラリは、ARM64デバイスではロードされません。build.gradleで常にabiFiltersを指定し、x86_64エミュレータだけでなく実際のデバイスでテストしてください。自動ABIフィルタリングにはAndroid App Bundleを使用してください。
3つ目のよくある間違いは頻繁なJNI呼び出しです。JavaとC++間の各遷移には約50〜100 nsかかります。JNIを介して10000要素の配列を1つずつ処理すると、オーバーヘッドが有用な作業を上回ります。配列全体を一度に渡してC++側で処理してください。
スレッドの問題も頻繁な間違いです。C++はstd::threadを起動できますが、JNIにアクセスできるのはJavaによって作成されたスレッドからのみです。C++スレッドからJavaメソッドを呼び出すには、JNIを介してAttachCurrentThread / DetachCurrentThreadを使用してください。
// C++スレッドからJavaを正しく呼び出す
JavaVM *g_vm; // JNI_OnLoadで取得したグローバルポインタ
void background_task() {
JNIEnv *env;
jint res = g_vm->AttachCurrentThread(&env, nullptr);
if (res == JNI_OK) {
jclass clazz = env->FindClass("com/example/App");
jmethodID mid = env->GetStaticMethodID(clazz, "onProgress", "(I)V");
env->CallStaticVoidMethod(clazz, mid, 100);
g_vm->DetachCurrentThread();
}
}よくある質問
Android NDK (Native Development Kit)は、アプリケーションの一部をCまたはC++で記述するためのツールキットです。パフォーマンスが重要なタスク、C/C++ライブラリのAndroidへのポーティング、UnityやUnreal Engine用のクロスプラットフォームコードの実装に使用されます。
Unityでは、ゲームロジックコードはC#で記述されますが、C++はAndroid NDKと組み合わせてプラグイン、ハードウェアアクセラレーション、カスタムC++ライブラリのポーティング、広告や分析用のネイティブSDKの統合に使用されます。
CMakeLists.txtは、ソースファイル、ライブラリ、コンパイルフラグを記述します。最小構成には、.soをビルドするためのadd_libraryと、Android logやその他のシステムライブラリをリンクするためのtarget_link_librariesが含まれます。
JNI (Java Native Interface)は、AndroidアプリのJava/KotlinコードとC++ライブラリの間の層です。C++がJavaから呼び出される場合、JNIは必須です。NDKを介して完全にC++コードを記述することもできますが、エントリポイントは通常、ネイティブ関数を呼び出すJava Activityです。
C++は、ゲーム、リアルタイムオーディオ/ビデオ処理、コンピュータビジョン、暗号化、物理シミュレーション、他のプラットフォームからのライブラリのポーティングに適しています。通常のUIアプリケーションには、Kotlinの方が効率的でシンプルです。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。