Здравствуйте, Chorkov, Вы писали:
C>Чем отличается время жизни строковых литералов в этих двух случаях? C>
...
C>
C>Есть ли гарантии, что константный строковый литерал доживет до конца времени жизни программы? C>Изменилось ли что-то в последних стандартах?
Был неправ, подозревая неверное время жизни строковых литералов.
После сублимации примера оказалось что указатели мусорные уже внутри цикла.
Это точно ошибка компилятора.
Сублимированный пример:
main.cpp:
#include <iostream>
struct record { const char* id; int count; };
void func ()
{
std::cout<< "func()" << std::endl;
#if 1
for( record r : std::initializer_list<record>{
{ "a", 1 },
{ "b", 2 },
})
{
std::cout<< (void*) r.id << std::endl; // print 00000000 (null)
std::cout<< r.id << std::endl; // fail there
}
#else// This variant work ok.for( record r : {
record{ "a", 1 },
record{ "b", 2 },
})
{
std::cout<< (void*) r.id << std::endl;
std::cout<< r.id << std::endl;
}
#endif
};
int main()
{
func ();
return 0;
}
Командная строка сборки:
C:\development\src\src\tests\test_rm1440>cl -Zc:rvalueCast -O2 main.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.11.25547 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
main.cpp
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\include\xlocale(314): warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\include\type_traits(2342): warning C4577: 'noexcept' used with no exception handling mode specified; termination on exception is not guaranteed. Specify /EHsc
Microsoft (R) Incremental Linker Version 14.11.25547.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:main.exe
main.obj
(Это минимальный набор флагов флагов компиляции, который приводит к ошибке.)
Здравствуйте, Chorkov, Вы писали:
C>Есть ли гарантии, что константный строковый литерал доживет до конца времени жизни программы?
Да.
C> std::map< const char* , size_t > counters;
Но нет никаких гарантий, что идентичные литералы должны обязательно иметь идентичные адреса. Поэтому, например, в твоём коде финальный размер словаря counters может принимать любое значенеие от 3 до 9 (в зависимости от деталей реализации).
Здравствуйте, Chorkov, Вы писали:
C>Это меня не очень волнует.
C>Проблема в том, что по выходе из foo литерал, похоже умер. Во всяком случа в foo()[0] — мусор. C>Хочу понять, ошибка компилятора или моя.
А точно при выходе из foo(), а не какой-то реальной функции, где было что-то отличное от return counters.begin()->first; ?
Здравствуйте, rg45, Вы писали:
R>Ну вот я бы не был так уверен. Даже если в примере по ссылке это так, не факт, что это так в примере у ТС.
В твоем примере деструкторы вызываются для временных объектов, создаваемых в цикле.
Здравствуйте, B0FEE664, Вы писали:
BFE>Согласен. Но перед тем как указатель начал использоваться для чего-то другого его значение было скопировано. BFE>Код примера равносилен следующему:
Я просто грешным делом попутал две разные проблемы. То, о чем думал я, показано в примере ниже: объект мапы не доживает до конца цикла.
C>Есть ли гарантии, что константный строковый литерал доживет до конца времени жизни программы?
Он доживет до конца времени нахождения в памяти данного бинарника: shared object/dll может быть выгружен задолго до завершения программы, а с ним уйдут и его литерали.
Как много веселых ребят, и все делают велосипед...
Здравствуйте, B0FEE664, Вы писали:
BFE>Согласен. Но перед тем как указатель начал использоваться для чего-то другого его значение было скопировано.
Ну да, я понял уже свою заблуждение. Я же как раз и предолагал, что указатель портится еще до копирования (помещения в мапу). Теперь мы убедились, что это не так — на gcc. Но ТС утверждает, что у него программа таки не работает, как ожидается. И, прежде, чем прийти к заключению, что портится именно литерал (что лично мне кажется мало вероятным), я бы все-таки убедился, что initializer_list доживает до конца цикла — на его компиляторе!
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, watchmaker, Вы писали:
W>Здравствуйте, Chorkov, Вы писали:
C>>Есть ли гарантии, что константный строковый литерал доживет до конца времени жизни программы? W>Да.
C>> std::map< const char* , size_t > counters; W>Но нет никаких гарантий, что идентичные литералы должны обязательно иметь идентичные адреса. Поэтому, например, в твоём коде финальный размер словаря counters может принимать любое значенеие от 3 до 9 (в зависимости от деталей реализации).
Это меня не очень волнует.
Проблема в том, что по выходе из foo литерал, похоже умер. Во всяком случа в foo()[0] — мусор.
Хочу понять, ошибка компилятора или моя.
Здравствуйте, Chorkov, Вы писали:
C>Проблема в том, что по выходе из foo литерал, похоже умер. Во всяком случа в foo()[0] — мусор. C>Хочу понять, ошибка компилятора или моя.
Умер не литерал, а объект класса record, вместе с инкапсулированным указателем.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, rg45, Вы писали:
R>Здравствуйте, Chorkov, Вы писали:
C>>Проблема в том, что по выходе из foo литерал, похоже умер. Во всяком случа в foo()[0] — мусор. C>>Хочу понять, ошибка компилятора или моя.
R>Умер не литерал, а объект класса record, вместе с инкапсулированным указателем.
Но, функция возвращает указатель именно на литерал.
Какая разница в каких живых и мертвых объектах побывала копия этого указателя?
Здравствуйте, Chorkov, Вы писали:
C>>>Проблема в том, что по выходе из foo литерал, похоже умер. Во всяком случа в foo()[0] — мусор. C>>>Хочу понять, ошибка компилятора или моя.
R>>Умер не литерал, а объект класса record, вместе с инкапсулированным указателем.
C>Но, функция возвращает указатель именно на литерал. C>Какая разница в каких живых и мертвых объектах побывала копия этого указателя?
Так она возвращает его уже после того, как владеющий объект record уже умер. И на том месте, где раньше был указатель, находится стековый мусор:
Здравствуйте, rg45, Вы писали:
R>>>Умер не литерал, а объект класса record, вместе с инкапсулированным указателем.
C>>Но, функция возвращает указатель именно на литерал. C>>Какая разница в каких живых и мертвых объектах побывала копия этого указателя?
R>Так она возвращает его уже после того, как владеющий объект record уже умер. И на том месте, где раньше был указатель, находится стековый мусор:
R>https://ideone.com/Igl57i
разрушение идет после того как указатель поместился мапу.
Здравствуйте, B0FEE664, Вы писали:
BFE>И что с того? Сам литерал остался жить и адрес его не менялся. Значит и указатель на "a" должен остаться валидным.
Адрес остался валидным. А указатель — область памяти хранившая этот адрес — к тому времени уже используется для чего-то другого.
Здравствуйте, night beast, Вы писали:
R>>https://ideone.com/Igl57i
NB>разрушение идет после того как указатель поместился мапу.
Ну вот я бы не был так уверен. Даже если в примере по ссылке это так, не факт, что это так в примере у ТС.
Главный вывод, который следует сделать, это то, что initializer_list до конца цикла не доживает. А значит и уверенности, что в момент записи в мапу элемент еще жив, быть не может.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, dead0k, Вы писали:
R>>Ну вот я бы не был так уверен. Даже если в примере по ссылке это так, не факт, что это так в примере у ТС. D>В твоем примере деструкторы вызываются для временных объектов, создаваемых в цикле.
Здравствуйте, rg45, Вы писали: R>А указатель — область памяти хранившая этот адрес — к тому времени уже используется для чего-то другого.
Согласен. Но перед тем как указатель начал использоваться для чего-то другого его значение было скопировано.
Код примера равносилен следующему:
Здравствуйте, 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.]
[Даю очевидные ответы на риторические вопросы]
Здравствуйте, watchmaker, Вы писали:
W>Здравствуйте, Chorkov, Вы писали:
C>>Есть ли гарантии, что константный строковый литерал доживет до конца времени жизни программы? W>Да.