Как найти утечку памяти в коде/проекте на С++?

Я программист на С++ на платформе Windows. Я использую Visual Studio 2008.

Я обычно заканчиваю код с утечками памяти.

Обычно я обнаруживаю утечку памяти, проверяя код, но он громоздкий и не всегда является хорошим подходом.

Поскольку я не могу позволить себе инструмент для обнаружения утечки памяти, я хотел, чтобы вы, ребята, предложили наилучшие способы избежать утечек памяти.

  • Я хочу знать, как программист может найти утечки памяти.
  • Существует ли какой-либо стандарт или процедура для обеспечения отсутствия утечки памяти в программе?

Ответ 1

Инструкция

Вещи, которые вам понадобятся

  • Знание в С++
  • Компилятор С++
  • Отладчик и другие поисковые программные средства

1

Понимать основы оператора. Оператор С++ "новый" выделяет кучную память. Оператор "delete" освобождает память кучи. Для каждого "нового" вы должны использовать "удалить", чтобы освободить выделенную вами память:

char* str = new char [30]; // Allocate 30 bytes to house a string.

delete [] str; // Clear those 30 bytes and make str point nowhere.

2

Перераспределить память, только если вы ее удалили. В приведенном ниже коде str получает новый адрес со вторым распределением. Первый адрес потерян безвозвратно, а также 30 байт, на которые он указал. Теперь их невозможно освободить, и у вас есть утечка памяти:

char* str = new char [30]; // Give str a memory address.

// delete [] str; // Remove the first comment marking in this line to correct.

str = new char [60]; /* Give str another memory address with
                                                    the first one gone forever.*/

delete [] str; // This deletes the 60 bytes, not just the first 30.

3

Следите за назначением указателя. Каждая динамическая переменная (выделенная память в куче) должна быть связана с указателем. Когда динамическая переменная становится отсоединенной от ее указателя (-ов), становится невозможно стереть. Опять же, это приводит к утечке памяти:

char* str1 = new char [30];

char* str2 = new char [40];

strcpy(str1, "Memory leak");

str2 = str1; // Bad! Now the 40 bytes are impossible to free.

delete [] str2; // This deletes the 30 bytes.

delete [] str1; // Possible access violation. What a disaster!

4

Будьте осторожны с локальными указателями. Указатель, объявляемый в функции, выделяется в стеке, но указанная динамическая переменная выделяется в куче. Если вы не удалите его, он будет сохраняться после выхода программы из функции:

void Leak(int x){

char* p = new char [x];

// delete [] p; // Remove the first comment marking to correct.

}

5

Обратите внимание на квадратные скобки после "delete". Используйте "delete" самостоятельно, чтобы освободить один объект. Используйте "delete" [] с квадратными скобками, чтобы освободить массив кучи. Не делайте ничего подобного:

char* one = new char;

delete [] one; // Wrong

char* many = new char [30];

delete many; // Wrong!

6

Если утечка еще разрешена - я обычно ищу ее с deleaker (проверьте здесь: http://deleaker.com).

Спасибо!

Ответ 2

Вы можете использовать некоторые методы в своем коде для обнаружения утечки памяти. Самый распространенный и самый простой способ обнаружения - определить макрос, скажем, DEBUG_NEW и использовать его вместе с предопределенными макросами, такими как __FILE__ и __LINE__, чтобы найти утечку памяти в вашем коде. Эти предопределенные макросы сообщают вам номер файла и строки утечек памяти.

DEBUG_NEW - это только MACRO, который обычно определяется как:

#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW

Итак, везде, где вы используете new, он также может отслеживать номер файла и строки, который может использоваться для обнаружения утечки памяти в вашей программе.

И __FILE__, __LINE__ являются предопределенными макросами, которые оценивают имя файла и номер строки соответственно, где вы их используете!

Прочитайте следующую статью, которая объясняет технику использования DEBUG_NEW с другими интересными макросами, очень красиво:

Кросс-платформенный детектор утечки памяти


Из Wikpedia,

Debug_new ссылается на технику в С++ для перегрузки и/или переопределения оператора новый и оператор удалить, чтобы перехватить выделение памяти и вызовы освобождения и, таким образом, отлаживать программа для использования памяти. Часто включает определение макроса с именем DEBUG_NEW и делает что-то вроде нового (_FILE_, _LINE_) для записи информации о файле/строке на выделение.. Microsoft Visual С++ использует этот метод в Microsoft Основы. Есть некоторые способы расширения этого метода, чтобы избежать с использованием переопределения макросов, возможность отображения файла/строки информацию о некоторых платформах. Там многие присущие этому ограничению метод. Он применяется только к С++ и не может улавливать утечки памяти с помощью C функции, такие как malloc. Однако он может быть очень простым в использовании, а также очень быстро, по сравнению с некоторыми более полные решения отладки памяти.

Ответ 3

Есть несколько известных методов программирования, которые помогут вам свести к минимуму риск утечки памяти из первых рук:

  • если вам нужно сделать собственное распределение динамической памяти, пишите new и delete всегда попарно и убедитесь, что код распределения/освобождения называется попарно
  • избегайте распределения динамической памяти, если можете. Например, используйте vector<T> t, если возможно, вместо T* t = new T[size]
  • используйте "умные указатели", например, повышайте интеллектуальные указатели (http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm)
  • мой личный фаворит: убедитесь, что вы поняли концепцию владения указателем и убедитесь, что везде, где вы используете указатели, вы знаете, какой объект кода является владельцем.
  • узнать, какие конструкторы/операторы присваивания автоматически создаются компилятором С++, и что это означает, если у вас есть класс, которому принадлежит указатель (или что это означает, если у вас есть класс, содержащий указатель на объект, который он не владеет).

Ответ 4

  • Загрузите Инструменты отладки для Windows.
  • Используйте утилиту gflags, чтобы включить трассировки стека пользовательского режима.
  • Используйте UMDH, чтобы сделать несколько снимков вашей памяти программ. Сделайте снимок до выделения памяти и сделайте второй снимок после того, как вы считаете, что ваша программа просочилась в память. Возможно, вы захотите добавить паузы или подсказки в своей программе, чтобы дать вам возможность запускать UMDH и делать снимки.
  • Запустите UMDH снова, на этот раз в своем режиме, который выполняет разницу между двумя моментальными снимками. Затем он сгенерирует отчет, содержащий стеки вызовов подозрительных утечек памяти.
  • Восстановите предыдущие настройки gflags, когда вы закончите.

UMDH предоставит вам больше информации, чем куча отладки CRT, потому что он наблюдает за распределением памяти по всему вашему процессу; он может даже сказать вам, протекают ли компоненты сторонних производителей.

Ответ 6

Запустить "Valgrind" можно:

1) Помогите определить утечки памяти - покажите, сколько у вас утечек памяти, и укажите на строки в коде, где была выделена утечка памяти.

2) Укажите неправильные попытки освободить память (например, неправильный вызов "delete")

Инструкция по использованию "Valgrind"

1) Получить Valgrind здесь.

1) Скомпилируйте ваш код с флагом -g

3) В вашей оболочке запустите:

valgrind --leak-check=yes myprog arg1 arg2

Где "myprog" - это ваша скомпилированная программа, а "arg1" - "arg2" - аргументы вашей программы.

4) Результатом является список вызовов malloc/new, у которых не было последующих вызовов для свободного удаления.

Например:

==4230==    at 0x1B977DD0: malloc (vg_replace_malloc.c:136)

==4230==    by 0x804990F: main (example.c:6)

Сообщает вам, в какой строке был вызван malloc (который не был освобожден).

Как указано другими, убедитесь, что для каждого "нового"/"malloc" вызова у вас есть последующий "удалить"/"бесплатный" вызов.

Ответ 7

Если вы используете gcc, там доступен gprof.

Я хотел знать, как программист находит утечку памяти

Некоторые из них используют инструменты, некоторые делают то, что вы делаете, также могут быть просмотрены с помощью экспертного анализа

Существует ли какой-либо стандарт или процедура, чтобы следить за утечкой памяти в программе

Для меня: всякий раз, когда я создаю динамически выделенные объекты, я всегда добавляю код освобождения, а затем заполняю код между ними. Это было бы нормально, если вы уверены, что между кодом не будет исключений. В противном случае я использую try-finally (я не часто использую С++).

Ответ 8

Найдите свой код для вхождений new и убедитесь, что все они встречаются внутри конструктора с соответствующим удалением в деструкторе. Убедитесь, что это единственная возможная операция метания в этом конструкторе. Простой способ сделать это - обернуть все указатели в std::auto_ptr или boost::scoped_ptr (в зависимости от того, нужна ли вам семантика перемещения). Для всего будущего кода просто убедитесь, что каждый ресурс принадлежит объекту, который очищает ресурс в своем деструкторе. Если вам нужна семантика перемещения, вы можете перейти к компилятору, который поддерживает ссылки на r-значение (по-моему, VS2010) и создавать конструкторы перемещения. Если вы не хотите этого делать, вы можете использовать множество сложных методов, связанных с добросовестным использованием swap, или попробовать библиотеку Boost.Move.

Ответ 9

  • В визуальной студии есть встроенный детектор для утечки памяти, называемый C Runtime Library. Когда ваша программа выйдет после возвращения основной функции, CRT проверит отладочную кучу вашего приложения. если у вас есть блоки, все еще выделенные на кучу отладки, тогда у вас есть утечка памяти.

  • Этот форум обсуждает несколько способов избежать утечки памяти в C/С++..

Ответ 10

Visual Leak Detector (VLD) - бесплатная, надежная система обнаружения утечки памяти с открытым исходным кодом для Visual С++.

Когда вы запускаете свою программу под отладчиком Visual Studio, Visual Leak Detector выведет отчет об утечке памяти в конце сеанса отладки. Отчет об утечке включает в себя полный стек вызовов, показывающий, как были распределены блокированные блоки памяти. Дважды щелкните по строке в стеке вызовов, чтобы перейти к этому файлу и строке в окне редактора.

Если у вас есть только аварийные дампы, вы можете использовать команду Windbg !heap -l, она обнаружит утечку блоков кучи. Лучше откройте опцию gflags: "Создайте базу данных трассировки стека пользователя", затем вы увидите стек вызовов распределения памяти.

Ответ 11

В Windows вы можете использовать CRT-отладочную кучу.

Существует ли какой-либо стандарт или процедура для обеспечения отсутствия утечки памяти в программе.

Да, не используйте ручное управление памятью (если вы когда-либо вызываете delete или delete[] вручную, то вы делаете это неправильно). Используйте RAII и интеллектуальные указатели, ограничьте выделение кучи на абсолютный минимум (большую часть времени, автоматические переменные будут достаточными).

Ответ 12

Отвечая на вторую часть вашего вопроса,

Существует ли какой-либо стандарт или процедура для обеспечения отсутствия утечки памяти в программе.

Да, есть. И это одно из ключевых различий между C и С++.

В С++ вы никогда не должны вызывать new или delete в вашем пользовательском коде. RAII - очень часто используемый метод, который в значительной степени решает проблему управления ресурсами. Каждый ресурс в вашей программе (ресурс - это все, что нужно получить, а затем - выпущено: файловые дескрипторы, сетевые сокеты, подключения к базе данных, а также простые распределения памяти, а в некоторых случаях - пары вызовов API (BeginX ( )/EndX(), LockY(), UnlockY()), должны быть завернуты в класс, где:

  • конструктор приобретает ресурс (вызывая new, если ресурс является распределением memroy)
  • деструктор освобождает ресурс,
  • копирование и назначение либо предотвращаются (делая частные конструкторы копирования и назначения), либо реализованы для правильной работы (например, путем клонирования базового ресурса).

Этот класс затем создается локально, в стеке или как член класса, а не путем вызова new и сохранения указателя.

Вам часто не нужно самостоятельно определять эти классы. Стандартные библиотеки библиотеки также ведут себя так, чтобы любой объект, хранящийся в std::vector, освобождался при уничтожении вектора. Поэтому не храните указатель в контейнере (для чего вам нужно будет звонить new и delete), а скорее сам объект (который дает вам управление памятью бесплатно). Аналогично, классы интеллектуального указателя могут использоваться для легкого переноса объектов, которые должны быть распределены с помощью new, и контролировать их время жизни.

Это означает, что когда объект выходит из области видимости, он автоматически уничтожается, а его ресурс освобождается и очищается.

Если вы будете делать это последовательно во всем коде, вы просто не будете иметь утечек памяти. Все, что может просочиться, привязано к деструктору, который, как гарантируется, будет вызываться, когда управление оставляет область, в которой был объявлен объект.

Ответ 13

AddressSanitizer (ASan) - это детектор ошибок быстрой памяти. Он обнаруживает ошибки переполнения use-after-free и {heap, stack, global} -buffer в программах на C/С++. Он находит:

  • Использовать после свободного (разыменовывание указателя)
  • Переполнение буфера кучи
  • Переполнение буфера стека
  • Глобальное переполнение буфера
  • Использовать после возврата
  • Ошибки порядка инициализации

Этот инструмент работает очень быстро. Среднее замедление инструментальной программы составляет ~ 2x.

Ответ 14

MTuner - это бесплатный инструмент для профилирования памяти, анализа и анализа утечек, поддерживающий компиляторы MSVC, GCC и Clang. Особенности включают:

  • история использования памяти и живых блоков памяти на временной шкале
  • мощная фильтрация операций с памятью на основе кучи, метки памяти, временного диапазона и т.д.
  • SDK для ручной аппаратуры с полным исходным кодом
  • поддержка непрерывной интеграции через использование командной строки
  • вызов стека и древовидная карта навигации
  • гораздо больше.

Пользователи могут профилировать любые платформы таргетинга на ПО с помощью GCC или Clang cross компиляторы. MTuner поставляется со встроенной поддержкой платформ Windows, PlayStation 4 и PlayStation 3.

Ответ 15

Вы можете использовать инструмент Valgrind для обнаружения утечек памяти.

Также, чтобы найти утечку в конкретной функции, используйте exit (0) в конце функции, а затем запустите ее с Valgrind

'$' valgrind ./your_CPP_program 

Ответ 16

Сравнение всех инструментов, известных человеку

Прежде всего, посмотрите на эту огромную таблицу в вики ASan: https://github.com/google/sanitizers/wiki/AddressSanitizerComparisonOfMemoryTools/d06210f759fec97066888e5f27c7e722832b0924

tcmalloc от gperftools от Google

https://github.com/gperftools/gperftools

Использование в Ubuntu 19.04:

sudo apt-get install google-perftools
gcc -ggdb3 -o main.out main.c -ltcmalloc
PPROF_PATH=/usr/bin/google-pprof \
  HEAPCHECK=normal \
  HEAPPROFILE=ble \
  ./main.out \
;
google-pprof main.out ble.0001.heap --text

Простая тестовая программа:

main.c

#include <stdlib.h>

void * my_malloc(size_t n) {
    return malloc(n);
}

void leaky(size_t n, int do_leak) {
    void *p = my_malloc(n);
    if (!do_leak) {
        free(p);
    }
}

int main(void) {
    leaky(0x10, 0);
    leaky(0x10, 1);
    leaky(0x100, 0);
    leaky(0x100, 1);
    leaky(0x1000, 0);
    leaky(0x1000, 1);
}

GitHub upstream.

Результат выполнения программы содержит анализ утечки памяти:

WARNING: Perftools heap leak checker is active -- Performance may suffer
Starting tracking the heap
Dumping heap profile to ble.0001.heap (Exiting, 4 kB in use)
Have memory regions w/o callers: might report false leaks
Leak check _main_ detected leaks of 272 bytes in 2 objects
The 2 largest leaks:
Using local file ./main.out.
Leak of 256 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581d3 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581b5 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start


If the preceding stack traces are not enough to find the leaks, try running THIS shell command:

pprof ./main.out "/tmp/main.out.24744._main_-end.heap" --inuse_objects --lines --heapcheck  --edgefraction=1e-10 --nodefraction=1e-10 --gv

If you are still puzzled about why the leaks are there, try rerunning this program with HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with HEAP_CHECK_MAX_POINTER_OFFSET=-1
If the leak report occurs in a small fraction of runs, try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of few hundred MB or with TCMALLOC_RECLAIM_MEMORY=false, it might help find leaks more re
Exiting with error code (instead of crashing) because of whole-program memory leaks

и вывод google-pprof содержит анализ использования кучи:

Using local file main.out.
Using local file ble.0001.heap.
Total: 0.0 MB
     0.0 100.0% 100.0%      0.0 100.0% my_malloc
     0.0   0.0% 100.0%      0.0 100.0% __libc_start_main
     0.0   0.0% 100.0%      0.0 100.0% _start
     0.0   0.0% 100.0%      0.0 100.0% leaky
     0.0   0.0% 100.0%      0.0 100.0% main

Вывод указывает нам на две из трех утечек:

Leak of 256 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581d3 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581b5 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start

Я не уверен, почему третий не появился

В любом случае, когда обычно, когда что-то протекает, это случается много раз, и когда я использовал это в реальном проекте, я просто очень легко указывал на функцию утечки.

Как уже упоминалось в выходных данных, это приводит к значительному замедлению выполнения.

Дополнительная документация по адресу:

Смотрите также: Как использовать TCMalloc?

Протестировано в Ubuntu 19.04, google-perftools 2.5-2.

Адрес Sanitizer (ASan) также от Google

https://github.com/google/sanitizers

Ранее упоминалось по адресу: Как найти утечку памяти в коде/проекте C++? TODO vs tcmalloc.

Это уже интегрировано в GCC, так что вы можете просто сделать:

gcc -fsanitize=address -ggdb3 -o main.out main.c
./main.out 

и результаты выполнения:

=================================================================
==27223==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 4096 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f210 in main /home/ciro/test/main.c:20
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

Direct leak of 256 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f1f2 in main /home/ciro/test/main.c:18
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f1d4 in main /home/ciro/test/main.c:16
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

SUMMARY: AddressSanitizer: 4368 byte(s) leaked in 3 allocation(s).

который четко определяет все утечки. Nice!

ASan также может выполнять другие интересные проверки, такие как запись за пределами поля: Обнаружено разрушение стека

Протестировано в Ubuntu 19.04, GCC 8.3.0.

Valgrind

http://www.valgrind.org/

Ранее упоминалось по адресу: fooobar.com/questions/54054/...

Использование:

sudo apt-get install valgrind
gcc -ggdb3 -o main.out main.c
valgrind --leak-check=yes ./main.out

Выход:

==32178== Memcheck, a memory error detector
==32178== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==32178== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==32178== Command: ./main.out
==32178== 
==32178== 
==32178== HEAP SUMMARY:
==32178==     in use at exit: 4,368 bytes in 3 blocks
==32178==   total heap usage: 6 allocs, 3 frees, 8,736 bytes allocated
==32178== 
==32178== 16 bytes in 1 blocks are definitely lost in loss record 1 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091B4: main (main.c:16)
==32178== 
==32178== 256 bytes in 1 blocks are definitely lost in loss record 2 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091D2: main (main.c:18)
==32178== 
==32178== 4,096 bytes in 1 blocks are definitely lost in loss record 3 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091F0: main (main.c:20)
==32178== 
==32178== LEAK SUMMARY:
==32178==    definitely lost: 4,368 bytes in 3 blocks
==32178==    indirectly lost: 0 bytes in 0 blocks
==32178==      possibly lost: 0 bytes in 0 blocks
==32178==    still reachable: 0 bytes in 0 blocks
==32178==         suppressed: 0 bytes in 0 blocks
==32178== 
==32178== For counts of detected and suppressed errors, rerun with: -v
==32178== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

Итак, еще раз, все утечки были обнаружены.

См. также: Как использовать valgrind для обнаружения утечек памяти?

Протестировано в Ubuntu 19.04, valgrind 3.14.0.

Ответ 17

В дополнение к инструментам и методам, предоставленным в других андерах, инструменты анализа статического кода могут использоваться для обнаружения утечек памяти (и других проблем). Бесплатным надежным инструментом является Cppcheck. Но есть много других доступных инструментов. Wikipedia содержит список инструментов анализа статического кода.

Ответ 18

Это может помочь кому-то, кто просто хочет использовать Visual Studio для обнаружения утечек. "Диагностические инструменты" с версиями VS 2015 и выше значительно улучшены. Также попробовал инструмент под названием "Deleaker", но инструмент Visual Studio в равной степени хорош. Наблюдение за следующим видео помогло мне начать работу.

https://www.youtube.com/watch?v=HUZW8m_3XvE

Ответ 19

Убедитесь, что вся куча памяти успешно освобождена. Нет необходимости, если вы никогда не выделяете память в куче. Если вы это сделаете, посчитайте, сколько раз вы использовали память malloc, и подсчитайте, сколько раз вы освобождаете память.

Ответ 20

Ни "new", ни "delete" никогда не должны использоваться в коде приложения. Вместо этого создайте новый тип, который использует идиому "менеджер/работник", в которой класс менеджера выделяет и освобождает память и перенаправляет все другие операции в рабочий объект.

К сожалению, это больше работы, чем следовало бы, потому что C++ не имеет перегрузки "оператор". Это еще больше работы при наличии полиморфизма.

Но это стоит потраченных усилий, потому что вам никогда не придется беспокоиться об утечках памяти, а значит, вам даже не придется их искать.