Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 31.07.2013, 17:35   #1
TRIZER
Студент
Пользователь
 
Аватар для TRIZER
 
Регистрация: 13.11.2009
Сообщений: 65
По умолчанию Ссылки, указатели, динамическая память, С++

Доброго дня.
Не могу найти ответа на свои вопросы. Возможно я неправильно ищу или я слепой.
Код вроде такого:
Код:
QByteArray & createPacket()
{
    QByteArray * byteArray = new QByteArray();
    
    return *byteArray;
}
и допустим напишу я вот так
Код:
...
{
QByteArray &test = createPacket();
}
...
Я думаю, что память не освободится, когда программа выйдет из зоны видимости ссылки test, т.к. память выделилась не в стеке, а сборщика мусора в С++ нет. Если верно, то выходит, в данном случае единственный верный вариант - использовать указатели. И явно высвобождать память.

Либо.
Код вроде такого:
Код:
QByteArray & createPacket()
{
    QByteArray byteArrayж
    
    return byteArray;
}
и допустим напишу я вот так
Код:
...
{
QByteArray &test = createPacket();
}
...
Я думаю, что:
после "return byteArray;" byteArray удалится, т.к. по идее, память для него выделилась в стеке и он не может физически там находиться после выхода из зоны видимости. (то есть он то находится, но скорее всего сотрется при вызове следующей функции). Таким образом снова не получается автоматизировать процесс выделения и освобождения памяти.

Скажите, правильно ли я думаю в обоих случаях, и если правильно - то как лучше поступать в таком случае (без лишних затрат памяти, времени, максимально удобно и безопасно)?
Заранее благодарен.
TRIZER вне форума Ответить с цитированием
Старый 31.07.2013, 19:15   #2
Helloween
Форумчанин
 
Регистрация: 24.04.2012
Сообщений: 300
По умолчанию

Зачем ты создаешь в классе объект этого же класса вообще?
Помог? Оставляем отзыв =)

Последний раз редактировалось Helloween; 31.07.2013 в 19:18.
Helloween вне форума Ответить с цитированием
Старый 31.07.2013, 20:07   #3
rrrFer
Санитар
Старожил
 
Аватар для rrrFer
 
Регистрация: 04.10.2008
Сообщений: 2,577
По умолчанию

Helloween
Цитата:
Зачем ты создаешь в классе объект этого же класса вообще?
МБ я ослеп, но как Вы узнали что "этого же класса"?

Цитата:
Скажите, правильно ли я думаю в обоих случаях, и если правильно - то как лучше поступать в таком случае (без лишних затрат памяти, времени, максимально удобно и безопасно)?
Заранее благодарен.
Создай свой класс, перегрузи в нем конструктор копирования, оператор присваивания, деструктор и следи что и в какой последовательности вызывается )) - но все эти тесты- не панацея, все может зависеть от оптимизаций компилятора.

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

В первом случае память должна течь, во второй - вроде бы нет, но оно работает? лишних копирований не происходит? - а-то мне чето кажется, что тут:
Код:
return byteArray;
создается новый объект, если это вобще взлетает.

Цитата:
а сборщика мусора в С++ нет....то как лучше поступать в таком случае (без лишних затрат памяти, времени, максимально удобно и безопасно)?
в С++ есть умные указатели, всякие std::move, перемещающие конструкторы (С++11) которые должны решать твою проблему.
Но, кроме того, в Qt есть чето типа сборщика мусора (он поможет не всегда - в твоем случае думаю никак не поможет, но часто - ты можешь сделать свои классы безопасными в этом плане если отнаследуешь их от QObject и в конструкторе не забудешь задать родителя) - я смотрю ты кьют используешь...
rrrFer вне форума Ответить с цитированием
Старый 31.07.2013, 20:51   #4
Helloween
Форумчанин
 
Регистрация: 24.04.2012
Сообщений: 300
По умолчанию

Цитата:
МБ я ослеп, но как Вы узнали что "этого же класса"?
эх, померещилось, вечер, усталость =)
Помог? Оставляем отзыв =)
Helloween вне форума Ответить с цитированием
Старый 31.07.2013, 23:29   #5
TRIZER
Студент
Пользователь
 
Аватар для TRIZER
 
Регистрация: 13.11.2009
Сообщений: 65
По умолчанию

Цитата:
В первом случае память должна течь, во второй - вроде бы нет, но оно работает? лишних копирований не происходит? - а-то мне чето кажется, что тут:
Код:

return byteArray;

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

Цитата:
в С++ есть умные указатели, всякие std::move, перемещающие конструкторы (С++11) которые должны решать твою проблему.
Но, кроме того, в Qt есть чето типа сборщика мусора (он поможет не всегда - в твоем случае думаю никак не поможет, но часто - ты можешь сделать свои классы безопасными в этом плане если отнаследуешь их от QObject и в конструкторе не забудешь задать родителя) - я смотрю ты кьют используешь...
Спасибо за совет. Почитаю на эту тему.
TRIZER вне форума Ответить с цитированием
Старый 01.08.2013, 01:14   #6
netrino
Участник клуба
 
Аватар для netrino
 
Регистрация: 15.07.2008
Сообщений: 1,933
По умолчанию

Никак из приведённых Вами способов делать нельзя - неочевидно и может привести к трудноуловимым ошибкам. Используйте указатели, либо умные указатели (QSharedPointer)
Код:
QByteArray * createPacket()
{
    QByteArray * byteArray = new QByteArray();
    
    return byteArray;
}

...
{
QByteArray *test = createPacket();
...
delete test;
}
...
Код:
QSharedPointer<QByteArray> createPacket()
{
    QSharedPointer<QByteArray> byteArray(new QByteArray());
    
    return byteArray;
}

...
{
QSharedPointer<QByteArray> test = createPacket();
}
...
Или умные указатели из стаднарта C++11, как рекомендовал rrrFer
Кроме того, QByteArray задействует технолгию "копирование при записи". Другими словами, массив данных не будет копироваться, пока не произойдёт запрос на запись.
Код:
QByteArray byteArray1("Hello")
QByteArray byteArray2 = byteArray1; // Копирования символов "Hello" не происходит
QByteArray byteArray3 = byteArray1; // то же самое
byteArray1.append(" world!"); // Здесь byteArray1 скопирует себе "Hello" из общего на всех изначального массива и прилеит " world!"
// При этом byteArray2 и byteArray3 по прожнему делят один и тот же массив
netrino вне форума Ответить с цитированием
Старый 01.08.2013, 01:17   #7
Rififi
Старожил
 
Регистрация: 19.08.2009
Сообщений: 2,119
По умолчанию

TRIZER

Я думаю, что память не освободится, когда программа выйдет из зоны видимости ссылки test, т.к. память выделилась не в стеке, а сборщика мусора в С++ нет. Если верно, то выходит, в данном случае единственный верный вариант - использовать указатели. И явно высвобождать память.

Верно.
В C++ можно несколько упростить себе жизнь, если использовать смарт-поинтеры, например:

QByteArray* createPacket() { return new QByteArray(); }
...
std::unique_ptr<QByteArray> p(createPacket());

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

В современных компиляторах можно сделать проще:

QByteArray createPacket() { return QByteArray(); }

либо будет работать return-value-optimization, либо move-конструктор. в обоих случаях дополнительных копий создано не будет.

второй вариант нежизнеспособный. т.к. к моменту возврата из функции стековая переменная будет уже уничтожена
Rififi вне форума Ответить с цитированием
Старый 01.08.2013, 13:38   #8
TRIZER
Студент
Пользователь
 
Аватар для TRIZER
 
Регистрация: 13.11.2009
Сообщений: 65
По умолчанию

netrino,
Цитата:
Кроме того, QByteArray задействует технолгию "копирование при записи". Другими словами, массив данных не будет копироваться, пока не произойдёт запрос на запись.
Да, действительно, спасибо, я этого не учитывал. Чуть не накосячил.

Rififi,
Цитата:
В C++ можно несколько упростить себе жизнь, если использовать смарт-поинтеры, например:

QByteArray* createPacket() { return new QByteArray(); }
...
std::unique_ptr<QByteArray> p(createPacket());

при выходе из области видимости память будет автоматически освобождена.
Спасибо за пример.
Цитата:
либо будет работать return-value-optimization, либо move-конструктор. в обоих случаях дополнительных копий создано не будет.
Спасибо не знал. Только не понятно, вот так например, работать return-value-optimization будет? (такой подход мне видится не очень красивым, но просто интересно)
Код:
QByteArray createPacket() 
{
 QByteArray test();
 return  test;
}
А про move конструкторы почитаю.
TRIZER вне форума Ответить с цитированием
Старый 01.08.2013, 16:45   #9
netrino
Участник клуба
 
Аватар для netrino
 
Регистрация: 15.07.2008
Сообщений: 1,933
По умолчанию

Цитата:
Сообщение от TRIZER Посмотреть сообщение
Спасибо не знал. Только не понятно, вот так например, работать return-value-optimization будет? (такой подход мне видится не очень красивым, но просто интересно)
Код:
QByteArray createPacket() 
{
 QByteArray test();
 return  test;
}
Будет (только это уже named-return-value-optimization, NRVO), но не забывайте, что только при конструировании нового объекта:
Код:
{
 QByteArray byteArray = createPacket()
}
В таком случае будет копия:
Код:
{
 QByteArray byteArray;
 byteArray = createPacket();
}
Цитата:
Сообщение от TRIZER Посмотреть сообщение
А про move конструкторы почитаю.
move-конструкторы - одна из новинок C++11, они могут быть не доступны на старых компиляторах.
netrino вне форума Ответить с цитированием
Старый 01.08.2013, 16:54   #10
TRIZER
Студент
Пользователь
 
Аватар для TRIZER
 
Регистрация: 13.11.2009
Сообщений: 65
По умолчанию

Всем спасибо ).
Было познавательно.
Тему можно считать закрытой.
TRIZER вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Указатели. Динамическая память. Kazik Помощь студентам 2 18.01.2014 00:17
Указатели. Динамическая память в С++ Solnze2 Помощь студентам 0 21.05.2011 10:47
Указатели.Динамическая память Solnze2 Паскаль, Turbo Pascal, PascalABC.NET 6 12.06.2010 10:08
Динамическая память. Пaвeл Помощь студентам 16 31.05.2009 21:16