C++ — мультипарадигмальна мова програмування з ручним керуванням пам'яттю, що поєднує процедурне, об'єктно-орієнтоване та узагальнене програмування. У мобільній розробці C++ використовується через Android NDK для портування бібліотек та через ігрові рушії Unity та Unreal Engine для створення кроссплатформених ігор. За даними TIOBE (2026), C++ входить до топ-5 мов за популярністю серед професійних розробників.
Головне
C++ — мова програмування, створена Б'єрном Страуструпом у 1985 році як розширення мови C з підтримкою класів. C++ забезпечує прямий доступ до пам'яті через вказівники, шаблонне метапрограмування та множинне успадкування. Стандарти C++17 та C++20 додали корутини, концепти та ranges.
На відміну від Java та Kotlin, C++ не має збирача сміття — розробник вручну керує виділенням та звільненням пам'яті через оператори new та delete. Це дає повний контроль над продуктивністю, але потребує дисципліни. За даними JetBrains Developer Survey (2025), 42% розробників C++ використовують мову в ігровій індустрії.
Стандарти C++ еволюціонують кожні три роки: C++11 (лямбди, auto, unique_ptr), C++14 (узагальнені лямбди), C++17 (if constexpr, filesystem), C++20 (модулі, корутини, концепти). Компілятори Clang та GCC підтримують усі актуальні стандарти, а Android NDK використовує Clang з тулчейну LLVM.
Головна відмінність C++ від мов JVM — ручне керування пам'яттю та компіляція в машинний код напряму. Java та Kotlin працюють поверх віртуальної машини з автоматичним збиранням сміття. Код C++ компілюється в нативний бінарний файл для конкретної архітектури — ARM, x86 або RISC-V.
| Критерій | C++ | Java / Kotlin |
|---|---|---|
| Керування пам'яттю | Ручне (new/delete, RAII) | Автоматичне (збирач сміття) |
| Компіляція | Нативний машинний код | Байт-код JVM / ART |
| Продуктивність | Максимальна (zero-cost abstractions) | Висока з паузами GC |
| Використання в мобільній розробці | NDK, ігри, бібліотеки | UI застосунки, бізнес-логіка |
| Збірка | CMake, NDK Build, Gradle + NDK | Gradle, Maven |
| Кроссплатформенність | Компіляція під кожну платформу | JVM / ART скрізь |
Android NDK (Native Development Kit) — інструментарій Google для написання частин Android-застосунку на C та C++. NDK включає тулчейн на основі Clang, системні заголовні файли Android, бібліотеки для налагодження та профілювання. Версія r27 (2025) підтримує C++20 та використовує LLVM 18.
NDK компілює код C++ у динамічні бібліотеки .so для архітектур ARM64, ARM32, x86 та x86_64. Застосунок на Java або Kotlin завантажує ці бібліотеки через System.loadLibrary() та викликає нативні функції через JNI. За даними Google, NDK завантажено понад 5 мільйонів разів.
Типовий проєкт з Android NDK містить папку app/src/main/cpp/ з вихідними файлами C++, CMakeLists.txt для збірки та Java-клас з оголошенням нативних методів. Gradle підключає NDK через блок externalNativeBuild у build.gradle.
// native-lib.cpp — простий JNI-метод для Android
#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());
}Код оголошує JNI-функцію з повним іменем Java_com_example_app_MainActivity_stringFromJNI — це угода JNI про іменування. Функція приймає вказівник на JNIEnv (середовище виконання) та jobject (екземпляр викликаючого класу). env->NewStringUTF створює Java-рядок з рядка C++.
Android підтримує кілька ABI (Application Binary Interface): arm64-v8a (64-бітні ARM пристрої, 99% сучасних смартфонів), armeabi-v7a (32-бітні ARM, застарілі пристрої), x86_64 (емулятори). NDK дозволяє збирати .so для кожної архітектури через фільтри ABI у build.gradle.
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++ у ядрі рушія для рендерингу та фізики. Навіть якщо розробник пише на C# у Unity, під капотом C++ керує графікою, звуком та фізичними розрахунками.
Unreal Engine побудований на C++ з нуля. Код ігрової логіки пишеться на C++ з використанням макросів UHT (Unreal Header Tool) для інтеграції з Blueprints — візуальною системою скриптингу. Класи успадковуються від базових типів AActor, UObject, UGameInstance з префіксними літерами U, A, F.
// Клас персонажа в 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++ застосовується в Native Plugins — .so бібліотеках для Android та .bundle для iOS. Через 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# маршалує виклик до функції C++ ProcessFrame через P/Invoke. Атрибут DllImport вказує ім'я .so бібліотеки. Функція C++ обробляє кадр у реальному часі та повертає результат. Такий підхід застосовується для пост-ефектів та комп'ютерного зору.
JNI (Java Native Interface) — стандартний механізм для виклику C/C++ коду з Java або Kotlin. В Android JNI — єдиний спосіб передати дані між віртуальною машиною ART та нативною бібліотекою. Кожен JNI-виклик має накладні витрати, тому дані передають пакетами, а не по одному полю.
JNIEnv — вказівник на таблицю функцій JNI. env->FindClass завантажує Java-клас, env->GetMethodID отримує ідентифікатор методу, env->CallVoidMethod викликає його. Для рядків використовується GetStringUTFChars та ReleaseStringUTFChars. JNI також підтримує глобальні та слабкі посилання на Java-об'єкти.
// Передача масиву байтів з C++ до Java через JNI
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-байтів. JNI_COMMIT у ReleaseByteArrayElements копіює зміни назад у Java-масив без звільнення пам'яті. Циклічна обробка виконується на CPU з максимальною продуктивністю C++ без пауз GC.
Головна небезпека JNI — витоки глобальних посилань. Кожен NewGlobalRef має бути звільнений через DeleteGlobalRef. Локальні посилання (що повертаються FindClass, NewStringUTF) автоматично видаляються при поверненні з нативної функції. Для інтенсивних викликів використовуйте PushLocalFrame / PopLocalFrame.
CMake — основний інструмент збірки для C++ в Android NDK. CMakeLists.txt описує цілі збірки, бібліотеки та залежності. Gradle викликає CMake через externalNativeBuild, передаючи шляхи до NDK та тулчейну. Альтернатива — NDK Build на основі Android.mk та Application.mk.
CMake 3.22+ підтримує пресети (CMakePresets.json) для різних конфігурацій: debug, release, profile з різними прапорами оптимізації. Для Android використовується тулчейн android.toolchain.cmake з NDK, що автоматично підставляється Gradle при збірці.
# CMakeLists.txt для Android NDK проєкту
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 — менеджер пакетів для C++ від Microsoft, що підтримує Android NDK як цільову платформу. Через vcpkg можна встановити Boost, OpenCV, SQLite, nlohmann-json та інші бібліотеки, скомпільовані для Android ABI. Vcpkg інтегрується з CMake через CMAKE_TOOLCHAIN_FILE.
C++ забезпечує максимальну продуктивність на мобільних пристроях завдяки компіляції в нативний код ARM та відсутності збирача сміття. За тестами Google (Android Performance Patterns, 2024), JNI-код на C++ виконується в 3–10 разів швидше за еквівалентний код Java для завдань з інтенсивними обчисленнями.
Ключові фактори продуктивності C++ на мобільних платформах: кеш-локальність (розміщення даних у неперервній пам'яті), SIMD-інструкції NEON для ARM, асинхронна робота з JNI через черги повідомлень. NEON — SIMD-розширення ARM, що дозволяє обробляти 128 біт даних за одну інструкцію, незамінне для обробки аудіо, відео та зображень.
// SIMD-обробка масиву через NEON intrinsics
#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 завантажує 4 float з пам'яті в 128-бітний NEON регістр. vmulq_f32 множить усі 4 елементи на 0.5 за один такт. vst1q_f32 зберігає результат назад. Без SIMD той самий цикл виконав би 4 множення послідовно — NEON дає прискорення до 4x для таких операцій.
| Операція | C++ (мс) | Java/Kotlin (мс) | Прискорення |
|---|---|---|---|
| Обробка зображення 1920x1080 | 12 | 45 | 3.75x |
| Швидке перетворення Фур'є (FFT) | 8 | 34 | 4.25x |
| Шифрування AES-256 блока 1MB | 3 | 18 | 6x |
| Стиснення даних ZLIB | 5 | 22 | 4.4x |
Перша і найнебезпечніша помилка — витік пам'яті. Кожен new повинен мати delete, кожен new[] — delete[]. На мобільних пристроях з обмеженою RAM будь-який витік призводить до OOM (Out Of Memory) та падіння застосунку. Використовуйте RAII через розумні вказівники: std::unique_ptr, std::shared_ptr, std::weak_ptr.
Друга помилка — ігнорування ABI-сумісності. Бібліотека, скомпільована для armeabi-v7a, не завантажиться на пристрої ARM64. Завжди вказуйте abiFilters у build.gradle та тестуйте на реальних пристроях, а не тільки емуляторі x86_64. Використовуйте Android App Bundle для автоматичної фільтрації ABI.
Третя типова помилка — часті JNI-виклики. Кожен перехід між Java та C++ коштує близько 50–100 нс. Якщо обробляти масив з 10000 елементів по одному через JNI, overhead перевищить корисну роботу. Передавайте дані масивами цілком та обробляйте на стороні C++.
Проблеми з багатопотоковістю — ще одна часта помилка. C++ може запускати std::thread, але звертатися до JNI можна тільки з потоку, створеного Java. Для виклику Java-методів з C++ потоку використовуйте AttachCurrentThread / DetachCurrentThread через JNI.
// Правильний виклик Java з C++ потоку
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 описує вихідні файли, бібліотеки та прапори компіляції. Мінімальна конфігурація включає add_library для збірки .so та target_link_libraries для прив'язки Android log та інших системних бібліотек.
JNI (Java Native Interface) — прошарок між Java/Kotlin кодом Android застосунку та бібліотекою C++. Якщо C++ викликається з Java, JNI обов'язковий. Можна писати код C++ повністю через NDK, але точка входу зазвичай Java-активність, що викликає нативні функції.
C++ виправданий для ігор, обробки аудіо/відео в реальному часі, комп'ютерного зору, криптографії, фізичних симуляцій та портування бібліотек з інших платформ. Для звичайного UI-застосунку Kotlin ефективніший і простіший.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.