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

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

Восстановить пароль Регистрация
 
relationer
33 / 0 / 0
Регистрация: 07.11.2013
Сообщений: 118
01.05.2014, 16:30     Куда деваются одномоментные указатели, или управление памятью в работе с std::string #1
Здравствуйте!

Положим, у нас есть функция, возвращающая строку 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 *>?
std::string и/или char* C++
Куда деваются данные из массива во время выполнения программы? C++
C++ Класс и конструктор с string или как использовать указатели.
C++ std:bad_alloc Проблемы с памятью
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
grizlik78
Эксперт C++
 Аватар для grizlik78
1882 / 1414 / 101
Регистрация: 29.05.2011
Сообщений: 2,958
01.05.2014, 16:58     Куда деваются одномоментные указатели, или управление памятью в работе с std::string #2
Стоит пользоваться первым вариантом и не забивать себе голову до тех пор, пока не станет точно известно (например с помощью профилировщика), чтоузкоем место именно здесь.
Да, компилятор может создавать временный объект и производить лишнее копирование, но как правило современные компиляторы поддерживают RVO (Return value optimization, оптимизация возвращаемого значения), метод оптимизации как раз для подобных случаев.
DrOffset
6424 / 3798 / 879
Регистрация: 30.01.2014
Сообщений: 6,591
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;
}
Avazart
 Аватар для Avazart
6897 / 5137 / 252
Регистрация: 10.12.2010
Сообщений: 22,578
Записей в блоге: 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
Ответ Создать тему
Опции темы

Текущее время: 02:38. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru