rg45:
R>Можно и поподробней. Пример я постарался сделать максимально упрощенным, поэтому к практическому смыслу используемых в нем сущностей прошу не придираться.
А теперь я приведу аналогию. Сначала один разработчик пишет:
void f(int i)
{
i*=10;
....
}
А потом некий другой разработчик говорит: "надо бы полученное в результате умножения i ещё увеличить на 5" и пишет:
void f(int i)
{
(i*=10)+=5;
....
}
где, естественно, получает undefined behavior, откуда некто делает вывод: оператор *= — это зло.
R>При запуске программы, до входа в main, выполняется инициализация объектов со статическим временем жизни (static storage duration). Такими объектами в этой программе являются константы my_home_directory и my_photo, определенные в заголовочном файле. По умолчанию константы в C++ имеют внутреннюю линковку (internal linkage). Это означает, что в каждом модуле, подключающем заголовочный файл header.h, будут созданы отдельные экземпляры каждой константы. Инициализация же этих констант будет происходить помодульно — сначала один модуль, потом другой. Но какой сначала, какой потом не известно, и в этом-то вся проблема.
В header.h можно extern const объявить, а в одном из cpp их определить.
header.h
extern const std::string my_home_directory;
extern const Path my_photo;
...
b.cpp
extern const std::string my_home_directory("D:\\Documents"); //имя моей домашней директорииextern const Path my_photo("my_photo.jpg"); //полный путь к файлу с моей любимой фотографией
Здравствуйте, D14, Вы писали:
D14>Здравствуйте, rg45, Вы писали:
R>>При запуске программы, до входа в main, выполняется инициализация объектов со статическим временем жизни (static storage duration). Такими объектами в этой программе являются константы my_home_directory и my_photo, определенные в заголовочном файле. По умолчанию константы в C++ имеют внутреннюю линковку (internal linkage). Это означает, что в каждом модуле, подключающем заголовочный файл header.h, будут созданы отдельные экземпляры каждой константы. Инициализация же этих констант будет происходить помодульно — сначала один модуль, потом другой. Но какой сначала, какой потом не известно, и в этом-то вся проблема.
D14>В header.h можно extern const объявить, а в одном из cpp их определить.
D14>
Можно, но это разруливает только данную, искусственно упрощенную ситуацию. Я ведь только хотел показать тебе, сам принцип возникновения ошибки, но не предполагал, что ты бросишься тут же ее устранять. А теперь представь, класс Path находится в сторонней библиотеке, которую разрабатывал независимый разработчик. Константа my_home_directory определена не тобой, а им. Пусть даже она имеет внешнюю линковку (объявлена как extern). Но расположена эта константа в модуле B.cpp доступа к которому у тебя нет и поместить в этот модуль свою константу ты не можешь. А как только ты заведещь свою констнту my_photo в модуле A.cpp, то получишь точно ту же проблему и extern-ами тут не спасешься.
Я одного не могу понять, чем вам так дорого использование типа const std::string для определение строковых констант? Почему не определять их как const char* const? Николай это обосновал: "Объектами std::string удобнее пользоваться". Но извините, создать экземпляр std::string на основе константы const char* const проще простого — неявное конструрование и готово, даже конструктор не надо писать. Пользователи этих констант сами смогут сделать это в любой момент и без какой-либо потери производительности. А если в жерву "удобствам" приносится надежность, то это уже не удобства, а медвежьи услуги.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, Николай Ивченков, Вы писали:
НИ>rg45:
R>>Можно и поподробней. Пример я постарался сделать максимально упрощенным, поэтому к практическому смыслу используемых в нем сущностей прошу не придираться.
НИ>А теперь я приведу аналогию. Сначала один разработчик пишет...
Использование аналогий в дискуссиях — один из приемов демагогии. Вот почитай, это интересно.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, rg45, Вы писали:
R>Можно, но это разруливает только данную, искусственно упрощенную ситуацию. Я ведь только хотел показать тебе, сам принцип возникновения ошибки, но не предполагал, что ты бросишься тут же ее устранять.
Ну, не такой уж и узкий класс разруливаемых проблем.
R>А теперь представь, класс Path находится в сторонней библиотеке, которую разрабатывал независимый разработчик.
rg45:
R>Использование аналогий в дискуссиях — один из приемов демагогии.
Для демонстрации сомнительности некоторых приёмов доказательства они вполне годятся. Всё твоё доказательство строится на аллегории "а представьте, что я сделаю вот так..." с получением негативных результатов. Я тоже так могу:
R>Но извините, создать экземпляр std::string на основе константы const char* const проще простого — неявное конструрование и готово, даже конструктор не надо писать.
Ну, попробуй вот так записать
#include <iostream>
#include <string>
const char* const my_home_directory("D:\\Documents");
int main()
{
std::string s = my_home_directory + '\\';
std::cout << s << std::endl;
}
и посмотри, что из этого выйдёт. Это, кстати, граблями не считается?
Здравствуйте, Николай Ивченков, Вы писали:
R>>Использование аналогий в дискуссиях — один из приемов демагогии.
НИ>Для демонстрации сомнительности некоторых приёмов доказательства они вполне годятся. Всё твоё доказательство строится на аллегории "а представьте, что я сделаю вот так..." с получением негативных результатов. Я тоже так могу:
НИ>Ну, попробуй вот так записать...
Похоже, наше изначально конструктивное обсуждение плавно перешло в банальные пререкания. Как мне кажется, мы оба уже вполне высказали свои точки зрения, поэтому предлагаю не тратить попусту время, и пусть широкая аудитория нас рассудит.
--
Не можешь достичь желаемого — пожелай достигнутого.