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) | Автоматическое (Garbage Collector) |
| Компиляция | Нативный машинный код | Байт-код 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() и вызывает native-функции через JNI. По данным Google, NDK скачан более 5 миллионов раз.
Типичный проект с Android NDK содержит папку app/src/main/cpp/ с исходными файлами C++, CMakeLists.txt для сборки и Java-класс с объявлением native-методов. 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-массив без освобождения памяти. For циклическая обработка выполняется на CPU с максимальной производительностью C++ без GC пауз.
Главная опасность JNI — утечки глобальных ссылок. Каждый NewGlobalRef должен быть освобождён через DeleteGlobalRef. Локальные ссылки (возвращаемые FindClass, NewStringUTF) автоматически удаляются при возврате из native-функции. Для интенсивных вызовов используйте 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-активность, вызывающая native-функции.
C++ оправдан для игр, обработки аудио/видео в реальном времени, компьютерного зрения, криптографии, физических симуляций и портирования библиотек с других платформ. Для обычного UI-приложения Kotlin эффективнее и проще.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.