Время жизни строковых литералов
От: Chorkov Россия  
Дата: 07.03.19 10:19
Оценка:
Чем отличается время жизни строковых литералов в этих двух случаях?
struct record { const char* id; int count; };

const char* foo()
{
    std::map< const char* , size_t > counters;
#if 1
    for( record r : std::initializer_list<record>{
            { "a", 1 },
            { "a", 2 },
            { "b", 3 },
            { "b", 4 },
            { "a", 5 },
            { "a", 6 },
            { "c", 7 },
            { "c", 8 },
            { "a", 9 },
        })
        counters[r.id]+=r.count ;
#else
    for( record r : {
            record{ "a", 1 },
            record{ "a", 2 },
            record{ "b", 3 },
            record{ "b", 4 },
            record{ "a", 5 },
            record{ "a", 6 },
            record{ "c", 7 },
            record{ "c", 8 },
            record{ "a", 9 },
        })
        counters[r.id]+=r.count ;
#endif
    return counters.begin()->first;
};


Есть ли гарантии, что константный строковый литерал доживет до конца времени жизни программы?
Изменилось ли что-то в последних стандартах?
Re: Время жизни строковых литералов
От: watchmaker  
Дата: 07.03.19 11:22
Оценка: +2
Здравствуйте, Chorkov, Вы писали:

C>Есть ли гарантии, что константный строковый литерал доживет до конца времени жизни программы?

Да.

C> std::map< const char* , size_t > counters;

Но нет никаких гарантий, что идентичные литералы должны обязательно иметь идентичные адреса. Поэтому, например, в твоём коде финальный размер словаря counters может принимать любое значенеие от 3 до 9 (в зависимости от деталей реализации).
Re[2]: Время жизни строковых литералов
От: Chorkov Россия  
Дата: 07.03.19 11:48
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Здравствуйте, Chorkov, Вы писали:


C>>Есть ли гарантии, что константный строковый литерал доживет до конца времени жизни программы?

W>Да.

C>> std::map< const char* , size_t > counters;

W>Но нет никаких гарантий, что идентичные литералы должны обязательно иметь идентичные адреса. Поэтому, например, в твоём коде финальный размер словаря counters может принимать любое значенеие от 3 до 9 (в зависимости от деталей реализации).

Это меня не очень волнует.

Проблема в том, что по выходе из foo литерал, похоже умер. Во всяком случа в foo()[0] — мусор.
Хочу понять, ошибка компилятора или моя.
Re[3]: Время жизни строковых литералов
От: rg45 СССР  
Дата: 07.03.19 13:28
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>Проблема в том, что по выходе из foo литерал, похоже умер. Во всяком случа в foo()[0] — мусор.

C>Хочу понять, ошибка компилятора или моя.

Умер не литерал, а объект класса record, вместе с инкапсулированным указателем.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Время жизни строковых литералов
От: Chorkov Россия  
Дата: 07.03.19 13:44
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, Chorkov, Вы писали:


C>>Проблема в том, что по выходе из foo литерал, похоже умер. Во всяком случа в foo()[0] — мусор.

C>>Хочу понять, ошибка компилятора или моя.

R>Умер не литерал, а объект класса record, вместе с инкапсулированным указателем.


Но, функция возвращает указатель именно на литерал.
Какая разница в каких живых и мертвых объектах побывала копия этого указателя?
Re[4]: Время жизни строковых литералов
От: B0FEE664  
Дата: 07.03.19 13:46
Оценка:
Здравствуйте, rg45, Вы писали:

R>Умер не литерал, а объект класса record, вместе с инкапсулированным указателем.


И что с того? Сам литерал остался жить и адрес его не менялся. Значит и указатель на "a" должен остаться валидным.

String literals have static storage duration, and thus exist in memory for the life of the program.

тут
И каждый день — без права на ошибку...
Re[5]: Время жизни строковых литералов
От: rg45 СССР  
Дата: 07.03.19 13:48
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>>>Проблема в том, что по выходе из foo литерал, похоже умер. Во всяком случа в foo()[0] — мусор.

C>>>Хочу понять, ошибка компилятора или моя.

R>>Умер не литерал, а объект класса record, вместе с инкапсулированным указателем.


C>Но, функция возвращает указатель именно на литерал.

C>Какая разница в каких живых и мертвых объектах побывала копия этого указателя?

Так она возвращает его уже после того, как владеющий объект record уже умер. И на том месте, где раньше был указатель, находится стековый мусор:

https://ideone.com/Igl57i

То, что в программа по ссылке выводит "ожидаемое" значение — просто случайность. UB — оно и в африке UB.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 07.03.2019 13:50 rg45 . Предыдущая версия .
Re[6]: Время жизни строковых литералов
От: night beast СССР  
Дата: 07.03.19 13:52
Оценка:
Здравствуйте, rg45, Вы писали:

R>>>Умер не литерал, а объект класса record, вместе с инкапсулированным указателем.


C>>Но, функция возвращает указатель именно на литерал.

C>>Какая разница в каких живых и мертвых объектах побывала копия этого указателя?

R>Так она возвращает его уже после того, как владеющий объект record уже умер. И на том месте, где раньше был указатель, находится стековый мусор:


R>https://ideone.com/Igl57i


разрушение идет после того как указатель поместился мапу.
Re[5]: Время жизни строковых литералов
От: rg45 СССР  
Дата: 07.03.19 13:54
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>И что с того? Сам литерал остался жить и адрес его не менялся. Значит и указатель на "a" должен остаться валидным.


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

Но, как показывает опыт, указатель, как и элемент initializer_list тоже остается валидным: http://rsdn.org/forum/cpp/7390822.1
Автор: rg45
Дата: 07.03.19
.

Тогда я сдаюсь
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 07.03.2019 14:06 rg45 . Предыдущая версия .
Re[7]: Время жизни строковых литералов
От: rg45 СССР  
Дата: 07.03.19 13:55
Оценка:
Здравствуйте, night beast, Вы писали:

R>>https://ideone.com/Igl57i


NB>разрушение идет после того как указатель поместился мапу.


Ну вот я бы не был так уверен. Даже если в примере по ссылке это так, не факт, что это так в примере у ТС.

Главный вывод, который следует сделать, это то, что initializer_list до конца цикла не доживает. А значит и уверенности, что в момент записи в мапу элемент еще жив, быть не может.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 07.03.2019 14:00 rg45 . Предыдущая версия .
Re[8]: Время жизни строковых литералов
От: dead0k  
Дата: 07.03.19 13:58
Оценка: 14 (1)
Здравствуйте, rg45, Вы писали:

R>Ну вот я бы не был так уверен. Даже если в примере по ссылке это так, не факт, что это так в примере у ТС.

В твоем примере деструкторы вызываются для временных объектов, создаваемых в цикле.
Re[9]: Время жизни строковых литералов
От: rg45 СССР  
Дата: 07.03.19 14:02
Оценка:
Здравствуйте, dead0k, Вы писали:

R>>Ну вот я бы не был так уверен. Даже если в примере по ссылке это так, не факт, что это так в примере у ТС.

D>В твоем примере деструкторы вызываются для временных объектов, создаваемых в цикле.

Гм... Да, ты прав: https://ideone.com/Igl57i
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[6]: Время жизни строковых литералов
От: B0FEE664  
Дата: 07.03.19 14:19
Оценка:
Здравствуйте, rg45, Вы писали:

R>А указатель — область памяти хранившая этот адрес — к тому времени уже используется для чего-то другого.

Согласен. Но перед тем как указатель начал использоваться для чего-то другого его значение было скопировано.
Код примера равносилен следующему:

const char* foo()
{
  const char* p1 = "a";
  const char* p2 = "a";
  const char* p3 = p1;
  p3 = p2;
  return p3; 
}

  точнее так
Надеюсь, что с const я ничего не напутал:

const char* foo()
{
  const char** p3;
  {
    const char* p1 = "a";
    const char* p2 = "a";

    p3 = new const char*;
    *p3 = p1;
    *p3 = p2;
  } 
  
  const char* p4 = *p3;
  delete p3;
  return p4; 
}
И каждый день — без права на ошибку...
Re[3]: Время жизни строковых литералов
От: andrey.desman  
Дата: 07.03.19 14:24
Оценка: +2
Здравствуйте, Chorkov, Вы писали:

C>Это меня не очень волнует.


C>Проблема в том, что по выходе из foo литерал, похоже умер. Во всяком случа в foo()[0] — мусор.

C>Хочу понять, ошибка компилятора или моя.

А точно при выходе из foo(), а не какой-то реальной функции, где было что-то отличное от return counters.begin()->first; ?
Re[7]: Время жизни строковых литералов
От: rg45 СССР  
Дата: 07.03.19 14:33
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

BFE>Согласен. Но перед тем как указатель начал использоваться для чего-то другого его значение было скопировано.


Ну да, я понял уже свою заблуждение. Я же как раз и предолагал, что указатель портится еще до копирования (помещения в мапу). Теперь мы убедились, что это не так — на gcc. Но ТС утверждает, что у него программа таки не работает, как ожидается. И, прежде, чем прийти к заключению, что портится именно литерал (что лично мне кажется мало вероятным), я бы все-таки убедился, что initializer_list доживает до конца цикла — на его компиляторе!
--
Не можешь достичь желаемого — пожелай достигнутого.
Re: Время жизни строковых литералов
От: Vain Россия google.ru
Дата: 08.03.19 14:25
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>Есть ли гарантии, что константный строковый литерал доживет до конца времени жизни программы?

оно статик сторедж, но нет гарантий что один и тот же

C>Изменилось ли что-то в последних стандартах?

Можно с помощью C++11 сконвертировать литерал в шаблонный класс чарактеров, а потом обратно, что будет гарантировать один и тот же адрес.
Фокус с захватом здесь: https://github.com/boostorg/hana/blob/master/include/boost/hana/string.hpp#L102
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[2]: Время жизни строковых литералов
От: SaZ  
Дата: 08.03.19 22:10
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Здравствуйте, Chorkov, Вы писали:


C>>Есть ли гарантии, что константный строковый литерал доживет до конца времени жизни программы?

W>Да.

А если это .dll которую выгрузили?
Re[7]: Время жизни строковых литералов
От: rg45 СССР  
Дата: 09.03.19 07:05
Оценка: 1 (1)
Здравствуйте, B0FEE664, Вы писали:

BFE>Согласен. Но перед тем как указатель начал использоваться для чего-то другого его значение было скопировано.

BFE>Код примера равносилен следующему:

Я просто грешным делом попутал две разные проблемы. То, о чем думал я, показано в примере ниже: объект мапы не доживает до конца цикла.

https://ideone.com/TI3hYc

#include <boost/range/adaptor/map.hpp>
#include <iostream>
#include <map>

std::map<int, const char*> makeMap()
{
    return {
        {1, "one"},
        {2, "two"},
        {3, "three"},
        {4, "four"},
        {5, "five"},
    };
}

int main()
{
    for (const char* value : makeMap() | boost::adaptors::map_values)
    {
        std::cout << " " << value;
    }
    std::cout << std::endl;
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Re: Время жизни строковых литералов
От: ononim  
Дата: 10.03.19 07:13
Оценка: 1 (1)
C>Есть ли гарантии, что константный строковый литерал доживет до конца времени жизни программы?
Он доживет до конца времени нахождения в памяти данного бинарника: shared object/dll может быть выгружен задолго до завершения программы, а с ним уйдут и его литерали.
Как много веселых ребят, и все делают велосипед...
Отредактировано 10.03.2019 7:13 ononim . Предыдущая версия .
Re[8]: Время жизни строковых литералов
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 10.03.19 07:37
Оценка:
Здравствуйте, rg45, Вы писали:


R>Я просто грешным делом попутал две разные проблемы. То, о чем думал я, показано в примере ниже: объект мапы не доживает до конца цикла.



R>
R>int main()
R>{
R>    for (const char* value : makeMap() | boost::adaptors::map_values)
R>    {
R>        std::cout << " " << value;
R>    }
R>    std::cout << std::endl;
R>}
R>


О, а что это за конструкт такой?
Маньяк Робокряк колесит по городу
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.