Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.63/8: Рейтинг темы: голосов - 8, средняя оценка - 4.63
33 / 0 / 0
Регистрация: 07.11.2013
Сообщений: 118
1

Куда деваются одномоментные указатели, или управление памятью в работе с std::string

01.05.2014, 16:30. Показов 1516. Ответов 4
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте!

Положим, у нас есть функция, возвращающая строку std::string, выглядящая как-то так:
C++
1
2
3
4
std::string getHome()
{
    return getenv("HOME");
}
Но есть один момент.
Если возвращаемое значение довольно большое, то подобная операция может быть слишком затратной. Я так понимаю, что для вызовов подобных методов компилятор генерирует что-либо такое:

C++
1
2
// Начало
std::string s = getHome();
Начало:
<Вызов метода getHome() - сохранение данных о вызове метода, если не inline>
<Выполнение команды getenv -> выделение памяти под значение в функции>
<Возврат из метода -> Выделение памяти под s на основании полученных данных>
<Копирование из выделенной памяти в методе в s>

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

Таким образом, первый вопрос: для подобных методов память выделяется дважды или один раз?

Далее. Пытаясь справиться с этим, я заменил сигнатуру getHome() на это:
C++
1
2
3
4
std::string& getHome()
{
    return getenv("HOME");
}
Компилятор ругнулся на меня понятием временного объекта. И, честно говоря, я его прекрасно понимаю.
Правда, именно из-за этой ситуации я решил, что память выделяется дважды.
Далее. Переделываем возвращаемое значение метода на указательное:
C++
1
2
3
4
std::string* getHome()
{
    return new std::string(getenv("HOME"));
}
Вроде бы все хорошо. Память выделяется только один раз, гарантированно, но...
А если мы используем подобное в выражениях типа:
C++
1
std::string s = "Your home dir is ..." + *getHome();
Итак, если я правильно понимаю внутреннее устройство std::string, для результирующей строки у нас выделяется новая память и туда _копируется_ содержимое обоих строк.
Стоп, а куда девается память, выделенная getHome()!? Она-ж зарезервирована! Утечка!
Можно, конечно, сделать вот так:
C++
1
2
3
std::string *pointer = getHome();
std::string s = "Nja" + *pointer;
delete pointer;
Но, как-то это все... слишком коряво...

И еще одно: сигнатуры некоторых методов из стандартной библиотеки для работы с std::string возвращают std::string&.
Как они это делают? Создают новый указатель - т. е. выделяют в куче независимо от меня память? А иначе же lvalue... И мне ее потом очищать вручную?

Собственно, как грамотно работать с std::string с точки зрения память, какие возращаемые типы указывать для подобных одномоментных функций, подобных указанной выше? Почему стандартные методы из std::string часто возвращают ссылку?
Генерирует ли компилятор двойное выделение памяти (и, как следствие, копирование возвращаемого значения)? Зависит ли это от степени оптимизации? Что происходит при контакенции строк при использовании std::string - если создается новая строка, использующая новую память, как очищать предыдущие ненужные? Как вообще грамотно распределять память в подобных случаях?

P. S. прошу заранее простить за несколько сумбурный и несколько несвязный стиль изложения.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
01.05.2014, 16:30
Ответы с готовыми решениями:

Ошибка terminate called after throwing an instance of 'std::bad_alloc' при работе с типом std::string
Добрый вечер, при работе функции возникает ошибка terminate called after throwing an instance...

Есть 4 потока. После осуществления блокировки барьером, 3 куда-то деваются, куда? (pthreads)
Друзья! Как мог упростил код, вот суть В цикле создаются 4 вспомогательных потока, кадый из...

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

ошибка error: cannot convert 'std::string {aka std::basic_string<char>}' to 'std::string* {aka std::basic_stri
на вод поступают 2 строки типа string. определить количество вхождений строки 2 в строку 1 ошибка...

4
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
01.05.2014, 16:58 2
Стоит пользоваться первым вариантом и не забивать себе голову до тех пор, пока не станет точно известно (например с помощью профилировщика), чтоузкоем место именно здесь.
Да, компилятор может создавать временный объект и производить лишнее копирование, но как правило современные компиляторы поддерживают RVO (Return value optimization, оптимизация возвращаемого значения), метод оптимизации как раз для подобных случаев.
1
18901 / 9859 / 2410
Регистрация: 30.01.2014
Сообщений: 17,304
01.05.2014, 17:06 3
Лучший ответ Сообщение было отмечено relationer как решение

Решение

relationer, во-первых читай про RVO.
во-вторых есть техника COW. std::string ее не использует (в новом стандарте это явно запрещено, в старых не пользовалось популярностью), но можно создать свой класс с такой реализацией или использовать готовый.
В третьих, в С++11 есть move semantics. А в предыдущих это реализуется вот этим паттерном.

Цитата Сообщение от relationer Посмотреть сообщение
C++
1
2
3
std::string *pointer = getHome();
std::string s = "Nja" + *pointer;
delete pointer;
Так лучше не делать. Ибо безопасность исключений.
Цитата Сообщение от relationer Посмотреть сообщение
сигнатуры некоторых методов из стандартной библиотеки для работы с std::string возвращают std::string&.Как они это делают?
Это надо каждый конкретный случай отдельно рассматривать.
Цитата Сообщение от relationer Посмотреть сообщение
Создают новый указатель - т. е. выделяют в куче независимо от меня память?
Нет. Давай конкретный пример - объясню.
Цитата Сообщение от relationer Посмотреть сообщение
И мне ее потом очищать вручную?
Нет.
Цитата Сообщение от relationer Посмотреть сообщение
Зависит ли это от степени оптимизации?
Зависит, если рассматривать твои первые примеры.
Цитата Сообщение от relationer Посмотреть сообщение
Что происходит при контакенции строк при использовании std::string - если создается новая строка, использующая новую память, как очищать предыдущие ненужные?
Создается новая строка. Очищают память деструкторы.
Цитата Сообщение от relationer Посмотреть сообщение
Как вообще грамотно распределять память в подобных случаях?
Вручную в данном случае ничего распределять не надо. Или тогда std::string не тот класс, который тебе нужен. "Грамотность" зависит от задачи и от результатов профилирования.

Добавлено через 1 минуту
Цитата Сообщение от relationer Посмотреть сообщение
Стоп, а куда девается память, выделенная getHome()!? Она-ж зарезервирована! Утечка!
Да, утечка. Не стоит так делать.
1
Заблокирован
01.05.2014, 17:32 4
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <sstream>
 
void GetHome (std::string *s)
{   *s = "HOME, sweet home )";
}
 
int main()
{   std::string s = "No home (";
    GetHome (&s);
 
    std::cout << s;
     
    std::cin.get();
    return 0;
}
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
01.05.2014, 22:20 5
Обычно через ссылку
C++
1
2
3
4
void GetHome (std::string& s)
{   
   s = "HOME, sweet home )";
}
0
01.05.2014, 22:20
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
01.05.2014, 22:20
Помогаю со студенческими работами здесь

Куда будет указывать указатель в std::map<string,pointer *>?
Чисто теоретически,хотелось бы узнать у знатоков C++ Допустим есть некий контейнер ...

Запись значения типа String^ в char* или std::string
String^ D1=textBox1-&gt;Text; Int32 D2=Convert::ToInt32(textBox2-&gt;Text); //god Int32...

Куда деваются комментарии?
Всем привет! Делаю поиск Сервис-&gt;Code Refernces. В окне &quot;Code Refernces&quot; появляется результат...

Где и почему используют ту или иную строку std::string, char[], System::String^ ?
Где и почему используют ту или иную строку std::string, char, System::String^ ? Объясните...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru