Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
relationer
33 / 0 / 0
Регистрация: 07.11.2013
Сообщений: 118
#1

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

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

Здравствуйте!

Положим, у нас есть функция, возвращающая строку 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. прошу заранее простить за несколько сумбурный и несколько несвязный стиль изложения.
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
01.05.2014, 16:30     Куда деваются одномоментные указатели, или управление памятью в работе с std::string
Посмотрите здесь:

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

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

Куда деваются байты при приведении типов? - C++
Всем доброго времени суток... Т.к. основной проект на c++, то пишу сюда... Непонятки с приведением типов, объясните пожалуйста... ...

Куда деваются данные из массива во время выполнения программы? - C++
Во время выполнения проги куда-то деваются данные из массива из стуктур. Почему так происходит? 1. Ввожу данные о 3 студентах в массив...

std::string и/или char* - C++
Здравствуйте. пишу метод построчной обработки данных из файла Вот он: bool loadFromFile(std::string fileName) { ...

Преобразовать const unsigned char* в std::string (или _bstr_t ) - C++
Здравствуйте старшие товарищи! Есть функция, которая возвращает результат типа const unsigned char*. а мне нужно получить ...

После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
grizlik78
Эксперт С++
1908 / 1440 / 110
Регистрация: 29.05.2011
Сообщений: 2,995
01.05.2014, 16:58     Куда деваются одномоментные указатели, или управление памятью в работе с std::string #2
Стоит пользоваться первым вариантом и не забивать себе голову до тех пор, пока не станет точно известно (например с помощью профилировщика), чтоузкоем место именно здесь.
Да, компилятор может создавать временный объект и производить лишнее копирование, но как правило современные компиляторы поддерживают RVO (Return value optimization, оптимизация возвращаемого значения), метод оптимизации как раз для подобных случаев.
DrOffset
7058 / 4199 / 949
Регистрация: 30.01.2014
Сообщений: 6,965
01.05.2014, 17:06     Куда деваются одномоментные указатели, или управление памятью в работе с std::string #3
Сообщение было отмечено автором темы, экспертом или модератором как ответ
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()!? Она-ж зарезервирована! Утечка!
Да, утечка. Не стоит так делать.
IrineK
Заблокирован
01.05.2014, 17:32     Куда деваются одномоментные указатели, или управление памятью в работе с std::string #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;
}
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.05.2014, 22:20     Куда деваются одномоментные указатели, или управление памятью в работе с std::string
Еще ссылки по теме:

Класс и конструктор с string или как использовать указатели. - C++
Есть такая вот ерунда class human { public: string name; string surname; int age; human(string *imya, string *familia,...

Как можно считывать из строки (std::string или char*) данные при помощи cin - C++
Как можно считывать из строки (std::string или char*) данные при помощи cin (или может есть какой-нибудь поток-обертка?), как sscanf из...

Как привести std::wstring к std::string? - C++
Как привести std::wstring к std::string?

Std::string and std::wstring convert - C++
случайно наткнулся на такую вот конвертацию std::string в std::wstring std::string text(&quot;text&quot;); ...

std:bad_alloc Проблемы с памятью - C++
Здравствуйте, проблема такая. Написал программу итерационного метода. Далее эту программу, поместил в функцию. И вызываю очень часто...

отсутствует оператор "<<" соответствующий этим операндам (std::ostream << const std::string) - C++
В 20 строке подсвечиваются красным знаки &lt;&lt;. Пишет, что &quot;отсутствует оператор &quot;&lt;&lt;&quot; соответствующий этим операндам (std::ostream &lt;&lt; const...


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

Или воспользуйтесь поиском по форуму:
Avazart
Эксперт С++
7115 / 5292 / 273
Регистрация: 10.12.2010
Сообщений: 23,398
Записей в блоге: 17
01.05.2014, 22:20     Куда деваются одномоментные указатели, или управление памятью в работе с std::string #5
Обычно через ссылку
C++
1
2
3
4
void GetHome (std::string& s)
{   
   s = "HOME, sweet home )";
}
Yandex
Объявления
01.05.2014, 22:20     Куда деваются одномоментные указатели, или управление памятью в работе с std::string
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru