Форум программистов, компьютерный форум, киберфорум
Наши страницы

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

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

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

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

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

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

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

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

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

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

4
grizlik78
Эксперт С++
1971 / 1464 / 122
Регистрация: 29.05.2011
Сообщений: 3,029
01.05.2014, 16:58 #2
Стоит пользоваться первым вариантом и не забивать себе голову до тех пор, пока не станет точно известно (например с помощью профилировщика), чтоузкоем место именно здесь.
Да, компилятор может создавать временный объект и производить лишнее копирование, но как правило современные компиляторы поддерживают RVO (Return value optimization, оптимизация возвращаемого значения), метод оптимизации как раз для подобных случаев.
1
DrOffset
7377 / 4454 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
01.05.2014, 17:06 #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()!? Она-ж зарезервирована! Утечка!
Да, утечка. Не стоит так делать.
1
IrineK
Заблокирован
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
Avazart
Эксперт С++
7236 / 5432 / 304
Регистрация: 10.12.2010
Сообщений: 24,144
Записей в блоге: 17
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
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.05.2014, 22:20
Привет! Вот еще темы с ответами:

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

запрошено преобразование от ‘const std::string*’ к нескалярному типу ‘std::string’ - C++
private: std::string firstName; }; std::string ClientData::getFirstName() const{ return firstName; } Дает в итоге...

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

На основе исходного std::vector<std::string> содержащего числа, создать std::vector<int> с этими же числами - C++
подскажите есть вот такая задача. Есть список . Создать второй список, в котором будут все эти же числа, но не в виде строк, а в виде...


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

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Опции темы

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