Указатели в циклах For - PullRequest
       53

Указатели в циклах For

3 голосов
/ 01 апреля 2010

Быстрый вопрос: я парень C #, отлаживающий приложение C ++, поэтому я не привык к управлению памятью.

В следующем коде:

for(int i = 0; i < TlmMsgDB.CMTGetTelemMsgDBCount(); i++)
  {
    CMTTelemetryMsgCls* telm = TlmMsgDB.CMTGetTelemetryMsg(i);
    CMT_SINT32_Tdef id = telm->CMTGetPackingMapID();

    ManualScheduleTables.SetManualMsg(i,id);
    ManualScheduleTables.SetManExec(i,false);
  }

Я теряю память каждую итерацию б / с CMTTelemetryMsgCls* telm = TlmMsgDB.CMTGetTelemetryMsg(i);? Метод «CMTGetTelemetryMsg (int)» возвращает указатель.

Должен ли я "delete telm;" в конце каждой итерации?

Ответы [ 7 ]

4 голосов
/ 01 апреля 2010

На этот вопрос нет глобального ответа.

Это действительно зависит от того, как человек реализовал функцию с возвращаемым значением.

  • Может возвращать переменную, выделенную в куче, и ожидать, что вы удалите ее
  • Может возвращать указатель на член-переменную даже не в куче
  • Если его возвращаемое значение находится в куче, TlmMsgDB может самостоятельно управлять памятью

Вам нужно посмотреть на реализацию вызываемой вами функции: TlmMsgDB.CMTGetTelemetryMsg

2 голосов
/ 01 апреля 2010

это зависит. если этот метод TlmMsgDB.CMTGetTelemetryMsg выделяет память, вы должны освободить ее. Если он просто возвращает указатель на что-то существующее, тогда не

1 голос
/ 01 апреля 2010

Все правы, это зависит. Тем не менее, это не поможет вам понять, нужно ли вам вызывать delete, кроме кого-то или чего-то, что говорит вам, каково это поведение. Я могу придумать пару способов понять это самостоятельно:

1) В вашем отладчике прервитесь перед началом цикла, затем остановите любую функцию, выделяющую память (например, malloc, mmap, brk), и посмотрите, остановится ли она. Это не просто доказательство, но вы можете попытаться обойти возвращаемый адрес и проверить адрес, который в конечном итоге возвращается функцией CMTGetPackingMapID.

2) Менее точный, но более простой способ сказать «происходит ли выделение вообще внутри этой функции» - это использовать вашу версию системы strace / ltrace. возможно, спать прямо перед циклом, чтобы было легко определить, где вы находитесь на трассе.

3) Наблюдайте за эквивалентом вершины вашей системы, чтобы увидеть, если вы лукавите

Обратите внимание, что C ++ - это злой язык, и ничто не может сказать вам наверняка, кроме кода. Например, нет ничего, что мешало бы фактически правильному поведению удалять некоторые элементы уровня 10 глубоко внутри объекта, на который у вас есть указатель. Или даже не дай бог освободить его (), потому что на самом деле класс вызывает malloc где-то глубоко в его глубинах.

1 голос
/ 01 апреля 2010

Не обязательно. Это зависит от внутренних функций TlmMsgDB.CMTGetTelemetryMsg (i).

Если он каждый раз возвращает новый объект («new Something ()»), то да, это утечка памяти, отсутствует какое-то управление памятью. Однако тот факт, что он называется «get», указывает на то, что он может создать объект один раз, а затем вернуть тот же указатель при повторном вызове. Наверное, так оно и есть.

Надеюсь, это немного прояснит ситуацию. :) Поначалу это немного странно. ;)

1 голос
/ 01 апреля 2010

Зависит. Проблема с использованием таких указателей заключается в том, что если вы не читаете документацию по функции CMTGetTelemetryMsg, вы не представляете, создал ли он новый указатель для вас и дал ли вам право владения, или если он просто дает вам указатель на внутренние данные ... это плохая практика. Если в документах говорится, что теперь у вас есть указатель, то да, вы должны удалять в каждом цикле. Если указатель принадлежит и управляется TlmMsgDB, то все в порядке.

1 голос
/ 01 апреля 2010

Если TlmMsgDB.CMTGetTelemetryMsg(i) выделяет и возвращает указатель на новый объект CMTTelemetryMsgCls, тогда да. Вы, вероятно, должны delete этот объект, когда закончите с ним, предполагая, что это безопасно. Библиотека, с которой вы работаете, также может выполнять какую-то сборку мусора, поэтому прочитайте документацию.

0 голосов
/ 01 апреля 2010

Попробуйте использовать профилировщик. Он может предоставить вам некоторую полезную информацию об управлении памятью, выполняемом внутри профилируемого процесса. Или, что еще лучше, вы можете использовать что-то вроде SoftICE, это позволяет вам устанавливать точку останова для любой функции, которая выделяет память, например HeapAllocEx. Используя такой инструмент, вы определенно определите реальное поведение стороннего кода даже без исходных текстов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...