Я пытаюсь изучить c ++ для проекта, и у меня возникла небольшая проблема с конкатенацией строк.
Мое приложение состоит из самого приложения и статически связанного проекта библиотеки.
В библиотеке я определил тип, представляющий путь в файловой системе, выступающий в качестве оболочки вокруг литерала пути std :: string.
Я определил функцию для объединения пути родительской папки с (предоставленным пользователем) именем самого файла / папки, добавляя при необходимости разделители пути.
Код функции выглядит следующим образом:
std::string normalize(std::string parentPath, const std::string& name) {
if (name.empty()) {
return parentPath;
} else {
parentPath.reserve(parentPath.length()+name.length()+1);
if (*name.begin() != Path::SEGMENT_SEPARATOR) {
parentPath.append(1,Path::SEGMENT_SEPARATOR);
}
if(*name.rbegin() != Path::SEGMENT_SEPARATOR){
parentPath.append(name);
}else{
parentPath.append(name.begin(), --name.end());
}
return parentPath;
}
}
(Путь :: SEGMENT_SEPARATOR — это константный символ ‘/’)
Проблема в следующем: каждый вызов string :: append, похоже, ничего не делает.
Я отладил функцию с помощью gdb, и содержимое parentPath не изменилось.
Я проверил пользовательский ввод, искал ‘/ 0’ или другие недопустимые символы на входе («имя»), но не нашел в этом ничего плохого.
Когда я переместил точно такую же функцию в проект приложения (из проекта библиотеки), она работала, как и ожидалось (с тем же вводом).
Оба проекта скомпилированы с использованием одного и того же набора инструментов (GCC 4.8.1 и используют диалект C ++ 11) и одинаковых параметров компилятора (все предупреждения включены, предупреждений в коде не поступало).
Есть ли в моем коде что-нибудь, что могло бы сломать string :: append таким образом?
РЕДАКТИРОВАТЬ: функция вызывается из:
Path::Path(const Path& parent, const std::string& name) : path_(normalize(parent.path_, name)) { }
Path::Path(const Path& parent, const char* name) : Path(parent, std::string(name)) {}
Который в свою очередь вызывается из (заголовочный файл):
extern const IO::Path CONFIG_PATH;
extern const IO::Path LANGUAGES_PATH;
С определением в файле cpp:
const IO::Path Game::CONFIG_PATH{"conf"};
const IO::Path Game::LOG_PATH{CONFIG_PATH,"log"};
Проверка объекта LOG_PATH показывает его значение элемента path_ как просто «conf» вместо «conf / log», как и ожидалось.
Могу ли я быть уверен, что CONFIG_PATH инициализируется до LOG_PATH, может ли это быть проблемой?
РЕДАКТИРОВАТЬ:
Я прочитал стандарт, и кажется, что вы не можете полагаться на какой-либо порядок инициализации глобальных переменных.
Это означает, что объявления CONFIG_PATH и LOG_PATH, очевидно, являются ошибками, и я, вероятно, должен заключить их в вызов функции следующим образом:
const IO::Path &getConfigPath(){
static IO::Path config{"conf"};
return config;
};
Может ли это быть причиной неудачного добавления строки?
Игнорируя причину вашей проблемы, я настоятельно рекомендую вам использовать эту простую версию:
std::string normalize(std::string parentPath, const std::string& name)
{
if (name.empty())
return parentPath;
else
{
if (name.front() != Path::SEGMENT_SEPARATOR)
parentPath += Path::SEGMENT_SEPARATOR;
if(name.back() != Path::SEGMENT_SEPARATOR)
parentPath += name;
else
parentPath.append(name.begin(), name.end()-1);
return parentPath;
}
}
Вы можете использовать
string str1, str2, strFinal;
strFinal = str1 + "some static string" + str2;
Что я думаю, что вы должны
Просто для справки:
std::string normalize(std::string parentPath, const std::string& name)
{
if (name.empty())
return parentPath;
else
{
if (name[0] != '/')
parentPath += '/';
if(name[name.length()-1] != '/')
parentPath += name;
else
parentPath.append(name.begin(), name.end()-1);
return parentPath;
}
}
Вот SSCCE, демонстрирующий, что ваша функция работает правильно. Проблема в коде, который вы есть не показывая нам.
Проблема почти наверняка заключается в некоторой проблеме конфигурации (несоответствие в параметрах компилятора, параметрах компоновщика или определениях препроцессора между двумя проектами), поскольку это не происходит, когда я объединяю два проекта в один.
Спасибо за комментарии к функции конкатенации: позже я переписываю ее в более читабельную форму.
Спасибо всем за полезные комментарии.
РЕДАКТИРОВАТЬ: обнаружил проблему.
Препроцессор #define, используемый для включения зависимой от linux реализации некоторых членов Path (в основном функции, создающей новые каталоги и файлы), был включен в основной проект, но не в библиотеку. Это, вероятно, вызвало проблему, когда библиотека была связана. Работает как шарм сейчас.