2013-08-18 1 views
0

Я пытаюсь изучить 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 является константной символ «/»)

Проблема заключается в следующем: каждый вызов строки :: Append, кажется, не делать ничего , Я отлаживал функцию с помощью gdb, а содержимое parentPath не менялось. Я проверил вход пользователя, ища «/ 0» или другие недопустимые символы на входе («имя»), но не нашел в этом ничего плохого.

Когда я переместил ту же самую функцию в проект приложения (из проекта библиотеки), она работала так, как ожидалось (с тем же вводом).

Оба проекта скомпилированы с использованием того же набора инструментов (GCC 4.8.1 и используют диалоги C++ 11) и те же параметры компилятора (все предупреждения включены, предупреждения не получены в коде). Есть ли что-нибудь в моем коде, которое могло бы сломать строку :: append таким образом?

EDIT: функция вызывается из:

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, может это проблема?

EDIT: Я прочитал стандарт и, похоже, вы не можете полагаться на какой-либо порядок инициализации для глобальных переменных. Это означает, что заявления CONFIG_PATH и log_path, очевидно, ошибки, и я, вероятно, следует завернуть их в вызов функции, как это:

const IO::Path &getConfigPath(){ 
    static IO::Path config{"conf"}; 
    return config; 
}; 

Может ли это быть, почему добавляемую строку не удается?

+2

Почему вы не используете '+' для concat строк? И вам не нужно резервировать перед добавлением. – deepmax

+0

Хорошо. Мне действительно интересно. Имеет ли 'push_back()' одна и та же проблема для отдельных символов или вообще ничего не меняет 'parentPath'? – WhozCraig

+0

см. Http://codepad.org/FyZh0ZMh, немного изменился, и он работает нормально – Saksham

ответ

2

Вы можете использовать

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; 
    } 
} 
+0

Есть ли разница между двумя (strFinal.append (str1) .append (str2) и strFinal = str1 + str2? – Hans

+0

нет, там нет разницы – Saksham

+0

Пробовал это с помощью оператора + вместо добавления: нет конкатенации. – Hans

2

Игнорирование причину вашей проблемы, я настоятельно рекомендую вам использовать этот простой версия:

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; 
    } 
} 
+0

Я переписал код, как было предложено (выглядит намного чище), но, похоже, нет никакой разницы. – Hans

+0

@Hans: Тогда ваша проблема, вероятно, где-то в вызывающем коде – celtschk

0

Проблема почти наверняка связана с проблемой конфигурации (несоответствие в параметрах компилятора, опциях компоновщика или препроцессорах defs между двумя проектами), поскольку это не происходит, когда я объединяю два проекта в один. Спасибо за комментарии к функции конкатенации: позже я переписал ее в более читаемую форму. Спасибо всем за полезные комментарии.

EDIT: обнаружена проблема. Препроцессор #define, используемый для включения зависимой от Linux реализации определенных элементов Path (главным образом, функции создания новых dirs и файлов), был включен в основном проекте, но не в библиотеке. Вероятно, это вызвало проблему, когда библиотека была связана. Сейчас работает как шарм.

+0

По меньшей мере, :) – Saksham

+0

Выполнено. Проблема действительно была вызвана директивой препроцессора, отсутствующей в библиотеке, где она использовалась для переключения «на» зависимой от Linux реализации определенных функций. Поскольку они присутствовали в исполняемом проекте, это, вероятно, нарушило процесс связывания. Думаю, теперь я знаю, что означает «неопределенное поведение» :). – Hans