LINUX.ORG.RU

Не понимаю C++: почему здесь не течет память?


0

4

Вот кусок исходника Qt:

QMimeData *QAndroidPlatformClipboard::mimeData(QClipboard::Mode mode)
{
    ...

    QMimeData *mimeData = new QMimeData();
    mimeData->setText(QtAndroidClipboard::clipboardText());
    return mimeData;
}

Не могу понять следующего: здесь создается объект типа QMimeData, ему выделяется память. Потом с этим объектом что-то делается (setText) и функция возвращает указатель на него.

Вопросы:

1. Почему не течет память? Где delete? Где очищается память, выделенная объекту?

2. Объясните, куда указывает указатель-результат вызова данной функции? Он указывает на созданный в функции объект QMimeData()? Но при выходе из scope это метода, данные объекта QMimeData должны стать невалидными, за них никто не поручится. Почему тогда возвращается указатель на данные, которые должны исчезнуть сразу после обращения?

★★★★★

Видел на первой странице.

anonymous
()

Почему не течет память? Где delete? Где очищается память, выделенная объекту?

Тебя не смущает, что объект куда-то возвращается? Что мы будем возвращать, если его тут же удалить?

vurdalak ★★★★★
()

Почему не течет память? Где delete? Где очищается память, выделенная объекту?

где-то есть delete. Ну например так:

QMimeData *zzz = mimeData(mode);
...
delete zzz;
emulek
()

2. память под объект выделяется в куче, так что невалидным объект не станет.

1. плюсов не знаю, но вангую, что ответственным за подчистку памяти будет caller.

MyTrooName ★★★★★
()

1. Потому что удаляется где-то в другом месте.
2. В корне не верные рассуждения. Указатель - это адресс в памяти. При создании объекта в памяти твоего процесса(а точнее в «куче» aka heap) выделяется блок памяти необходимого размера и оператор new (или ф. malloc) возвращает адресс начала этого блока. Когда возвращается указатель, то возвращается по сути число. При выходе из скопа ничего с выделенной таким образом областью памяти не происходит.

Если бы объект был создан в стэке как

QMimeData mimeData;
тогда да, тогда бы возврат адресса на него был бы - ошибкой, потому что объект бы был удалён

invy ★★★★★
()
Последнее исправление: invy (всего исправлений: 1)

ну в c++ это обычная практика:

class foo
{
    char *x;
public:
    foo() : x(NULL)
    {}
    char *f1()
    {
        return new char[1232];
    }
    void f2()
    {
        x = f1();
    }
    virtual ~foo()
    {
        delete[] x;
    }
};

тут delete в деструкторе, и оно не срабатывает, если f2() не запустилась, потом что delete NULL ничего не делает.

emulek
()

delete будет вызывать тот кто получил указатель на объект. Тред.

KblCb ★★★★★
()

Попробуй посмотри этот же код после прохода moc, по-идее, должно стать понятнее.

eagleivg ★★★★★
()

В «кусках» кода память и не может течь. Давай весь код. К тому же это Qt, который разительно от pure c++ отличается.

А вопрос вообще не имеет смысла.

unt1tled ★★★★
()

Он и в prog.org.ru тред создал...

А вообще он прав - QClipboard::mimeData, если верить документации, выдаёт константный указатель на данные буфера обмена, нигде не сказано, что контроль за удалением передаётся в наши руки.

Более того, гляньте на исходники qandroidplatformintegration.h/cpp:

Хидер

...
private:
    QPlatformClipboard *m_androidPlatformClipboard;
...

Конструктор

    ...
    m_androidPlatformClipboard = new QAndroidPlatformClipboard();
    ...

В деструкторе ни слова о m_androidPlatformClipboard. Более того, этот указатель вообще не используется нигде

QPlatformClipboard *QAndroidPlatformIntegration::clipboard() const
{
static QAndroidPlatformClipboard *clipboard = 0;
    if (!clipboard)
        clipboard = new QAndroidPlatformClipboard;

    return clipboard;
}
Adonai ★★★
()

Эталонные крестопроблемы новичков =) Когда ты используешь new, весь scope идет нахрен. Никто и не говорил, что там память не течет - для этого недостаточно информации.

Исползуй Java или C# люк! Или хотя бы Haskell если нужна быстрота!

stevejobs ★★★★☆
()
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: комментарий от stevejobs

Эталонные крестопроблемы новичков

да

Исползуй Java или C# люк! Или хотя бы Haskell если нужна быстрота!

нет

emulek
()

В скопе нет объекта QMimeData. Есть только указатель типа QMimeData*. Он и отвалится при выходе из скопа, но в нём и так ничего интересного нет.

Miguel ★★★★★
()
Ответ на: комментарий от Miguel

В скопе нет объекта QMimeData. Есть только указатель типа QMimeData*. Он и отвалится при выходе из скопа, но в нём и так ничего интересного нет.

В нем есть адрес данных объекта QMimeData.

Память действительно в этом месте течет.

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

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Память действительно в этом месте течет.

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

Miguel ★★★★★
()
Ответ на: комментарий от Miguel

В том-то и дело, что уровнем выше считается, что это указатель на поле класса (на платформах помимо андроида), и ничего не удаляется.

Пример для QNX

QMimeData *QQnxClipboard::mimeData(QClipboard::Mode mode)
{
    if (mode != QClipboard::Clipboard)
        return 0;

    if (m_mimeData->userMimeData())
        return m_mimeData->userMimeData();

    m_mimeData->clear();

    return m_mimeData;
}
Adonai ★★★
()
Последнее исправление: Adonai (всего исправлений: 1)
Ответ на: комментарий от Adonai

В том-то и дело, что уровнем выше считается, что это указатель на поле класса (на платформах помимо андроида), и ничего не удаляется.

В крайнем случае, это означает, что утечка памяти выше уровнем. А вообще, надо смотреть, как оно используется.

Miguel ★★★★★
()

В Qt есть автоматическая «почти сборка мусора», а именно - наследники QObject, при их удалении, автоматически убивают своих детей (под детьми подразумевается объект у которого задан parent).

Конкретно тут - думаю что содержимое буфера обмена «удаляется» самой системой, при необходимости (например когда вы копируете в буфер что-то другое).

RiseOfDeath ★★★★
()
Последнее исправление: RiseOfDeath (всего исправлений: 4)
Ответ на: комментарий от nanoolinux

ну в c++ это очередной отстрел ноги.

почему?

1. Память всегда освобождается.

2. Память освобождается строго 1 раз

3. Не выделяется память если она не нужна

4. Можно выделить память дважды, но это лечится:

if(p)// не помню: я уже выделил память?
  delete p;// таки выделил
p = new X[100500];// яхз что выделил, сейчас надо 100500 Х

не вижу проблемы...

emulek
()
Ответ на: комментарий от emulek

почему?

foo *p = new foo;
p->f2();
p->f2(); //не помню, вызывал я или нет, давай ещё раз на всякий случай
delete p; //<- leak.

Да и вообще, нахер нужен этот foo? Eсть std::unique ptr<T []> и std::vector. Всё остальное не нужно.

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

p->f2(); //не помню, вызывал я или нет, давай ещё раз на всякий случай

ну это же просто пример, IRL там конечно проверка стоит.

Да и вообще, нахер нужен этот foo? Eсть std::unique ptr<T []> и std::vector. Всё остальное не нужно.

для таких как ты есть php. И другие ЯП, в которых есть всё необходимое.

emulek
()
Ответ на: комментарий от emulek

для таких как ты есть php

А для таких как ты - С. В 21 веке в спп байтики туда сюда никто не перекладывает. А вот это вот

if (p)
 delete p;
из разряда «когда я вырасту - пойду в школу, а то детский садик уже надоел.».

nanoolinux ★★★★
()
Ответ на: комментарий от nanoolinux

В 21 веке в спп байтики туда сюда никто не перекладывает. А вот это вот

из разряда «когда я вырасту - пойду в школу, а то детский садик уже надоел.».

можешь смеяться, но именно в этой ерунде и заключается сила C/C++. А если тебе нужно автоматическое управление памятью, то поверь: во всяких java оно организовано намного лучше и удобнее, чем в твоей любимой STL.

emulek
()
Ответ на: комментарий от lovesan

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

grouzen ★★
()
Ответ на: комментарий от lovesan

а все потому, что ты не влезаешь сюда со своим большим и важным мнением

thread уныл

TC ленив

/thread

anonymous
()

эмм, деструктор?

//я не очень в ООП разбираюсь

Andersen ★★
()
Ответ на: комментарий от anonymous

Он про то, что проверка на 0 не нужна при удалении указателя.

он идиот в таком случае.

я же писал: «тут delete в деструкторе, и оно не срабатывает, если f2() не запустилась, потом что delete NULL ничего не делает.» Не понимаю C++: почему здесь не течет память? (комментарий)

emulek
()
Ответ на: комментарий от anonymous

и да, у меня проверка не NULL нужна совсем не для delete, а для того, что-бы не выделить память повторно. IRL вместо delete может быть код, который не удаляет память, а подготавливает то, что есть для нового использования.

emulek
()
Ответ на: комментарий от emulek

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

Тогда if (!ptr) return; следует поместить как раз в этот код. Потому что ожидается, что delete 0; ничего не делает.

ilammy ★★★
()
Ответ на: комментарий от ilammy

Тогда if (!ptr) return; следует поместить как раз в этот код. Потому что ожидается, что delete 0; ничего не делает.

ну оно и есть в этом коде. У меня «весь код» это delete, просто для примера.

emulek
()
Ответ на: комментарий от x0r

охеренный тред, Xintrea ты лучший.

Вот, а вы что-то против PHP-программистов ещё имеете :D

KRoN73 ★★★★★
()
Ответ на: комментарий от Miguel

Мотороллер не мой, оказалось, баг такой был, так что конкретизировал в комментарии

Adonai ★★★
()

Пришел ответ:

Hi and welcome to devnet,
For the first point, it’s not necessarily a bug, the handling might be done differently on Android. However I encourage you to ask this on the developer mailing list you’ll find Qt’s developers/maintainers there (this forum is more user oriented)
For the second point, indeed, the clipboard is allocated twice and not deleted in the destructor in the case of the member variable. A patch for that has been submitted.

Adonai ★★★
()
Последнее исправление: Adonai (всего исправлений: 1)
Ответ на: комментарий от lovesan

Это точно, бро. Вот я не позже, чем в тяпницу, замутил прогу, которая генерирует код в рантайме. Зашибись, да?

Это я сделал, чтобы раскрутить циклы. Вот портянка на C:

http://pastebin.com/T8H7wGuw

Это так модно и молодежно, хотя и ничего не дало (это даже ничего не дает и в коде на C). Но теперь мне очень хочется поговорить, как это круто: генерировать код. А ты часто генерируешь код в рантайме (eval'ом, я имею в виду)

vonenij
()

Правильный вопрос. Не понимаю, почему все так возбудились и начали писать негативные комментарии. ТС заметил обычный баг.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Удваиваю. Мне пришел ответ от разработчиков Qt, что патч уже отправлен на рассмотрение.

For the second point, indeed, the clipboard is allocated twice and not deleted in the destructor in the case of the member variable. A patch for that has been submitted.

Adonai ★★★
()
Последнее исправление: Adonai (всего исправлений: 2)
Ответ на: комментарий от Adonai

Тьфу, не то процитировал.

Вот правильное:

Adonai: Thanks, the mimeData should be released, or at least not re-created.

Adonai ★★★
()
28 февраля 2014 г.
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.