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

(Path::SEGMENT_SEPARATOR は const char '/' です)

問題はこれです: 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)) {}

次に、from(ヘッダーファイル)と呼ばれます:

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/log」ではなく「conf」として表示されます。CONFIG_PATH が LOG_PATH の前に初期化されていることを確認できますか? これが問題になる可能性はありますか?

編集: 標準を読みましたが、グローバルの初期化順序に依存できないようです。これは、CONFIG_PATH と LOG_PATH の宣言が明らかにエラーであることを意味し、おそらく次のような関数呼び出しにラップする必要があります。

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

これが、文字列の追加が失敗する理由ですか?

4

4 に答える 4

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;
    }
}
于 2013-08-18T09:00:30.213 に答える
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;
    }
}
于 2013-08-18T08:56:23.657 に答える
2

これは、関数が正しく機能することを示す SSCCEです。問題は、あなたが私たちに見せていないコードにあります。

于 2013-08-18T09:23:55.967 に答える
0

この問題は、2 つのプロジェクトを 1 つにマージした場合には発生しないため、ほぼ確実に何らかの構成の問題 (2 つのプロジェクト間のコンパイラ オプション、リンカー オプション、またはプリプロセッサ定義の不一致) です。連結関数に関するコメントありがとうございます。後で、より読みやすい形式に書き直します。有益なコメントをくださった皆様に感謝します。

編集:問題が見つかりました。パスの特定のメンバー (主に新しいディレクトリとファイルを作成する関数) の Linux 依存実装をオンにするために使用されるプリプロセッサ #define は、メイン プロジェクトではオンになりましたが、ライブラリではオンになりませんでした。これは、ライブラリがリンクされたときに問題を引き起こした可能性があります。今では魅力のように機能します。

于 2013-08-18T10:20:45.380 に答える