3

これを叩き続けて申し訳ありませんが、私は学ぼうとしています:)。これはいいですか?そして、はい、私はメモリリークを気にします。クロスプラットフォームの方法がないように思われるため、char*を事前に割り当てる適切な方法を見つけることができません。

const string getcwd()
{
    char* a_cwd = getcwd(NULL,0);
    string s_cwd(a_cwd);
    free(a_cwd);
    return s_cwd;
}

UPDATE2:BoostまたはQtがないと、最も一般的なものが長引く可能性があります(受け入れられた回答を参照)

4

7 に答える 7

7

標準のままにしたい場合getcwdは、NULL を渡しても何もする必要はありません。代わりに、ほとんどの場合に「十分な大きさ」のバッファ (たとえば 255 文字) をスタックに割り当てる必要がありますが、 でgetcwd失敗する可能性がある場合に備えてくださいerrno==ERANGE。その場合、より大きなバッファーを動的に割り当て、必要に応じてそのサイズを大きくする必要があります。

このようなものが機能する可能性があります(注意:テストされておらず、スクラッチで書かれただけで、確実に改善できます):

string getcwd()
{
    const size_t chunkSize=255;
    const int maxChunks=10240; // 2550 KiBs of current path are more than enough

    char stackBuffer[chunkSize]; // Stack buffer for the "normal" case
    if(getcwd(stackBuffer,sizeof(stackBuffer))!=NULL)
        return stackBuffer;
    if(errno!=ERANGE)
    {
        // It's not ERANGE, so we don't know how to handle it
        throw std::runtime_error("Cannot determine the current path.");
        // Of course you may choose a different error reporting method
    }
    // Ok, the stack buffer isn't long enough; fallback to heap allocation
    for(int chunks=2; chunks<maxChunks ; chunks++)
    {
        // With boost use scoped_ptr; in C++0x, use unique_ptr
        // If you want to be less C++ but more efficient you may want to use realloc
        std::auto_ptr<char> cwd(new char[chunkSize*chunks]); 
        if(getcwd(cwd.get(),chunkSize*chunks)!=NULL)
            return cwd.get();
        if(errno!=ERANGE)
        {
            // It's not ERANGE, so we don't know how to handle it
            throw std::runtime_error("Cannot determine the current path.");
            // Of course you may choose a different error reporting method
        }   
    }
    throw std::runtime_error("Cannot determine the current path; the path is apparently unreasonably long");
}

ところで、あなたのコードには非常に間違ったことがあります: a_cwd の割り当てを解除しようとしています (これはおそらく、標準外の拡張機能では、malloc または他のメモリ割り当て関数で割り当てられます。getcwd は C で使用されると考えられているためdeleteです)。絶対にそうすべきではありません。各割り当て方法には対応する割り当て解除があり、それらが一致していてはならないことに注意してください。

于 2010-05-19T21:45:06.573 に答える
3

buf引数getcwdが NULLの場合、どちらも自動割り当て動作をサポートしているため、これは Windows と Linux で機能します。ただし、この動作は標準ではないため、より難解なプラットフォームでは問題が発生する可能性があることに注意してください。

ただし、この動作に依存せずに実行できます。

const string getcwd()
{
    size_t buf_size = 1024;
    char* buf = NULL;
    char* r_buf;

    do {
      buf = static_cast<char*>(realloc(buf, buf_size));
      r_buf = getcwd(buf, buf_size);
      if (!r_buf) {
        if (errno == ERANGE) {
          buf_size *= 2;
        } else {
          free(buf);
          throw std::runtime_error(); 
          // Or some other error handling code
        }
      }
    } while (!r_buf);

    string str(buf);
    free(buf);
    return str;
}

上記のコードは 1024 のバッファー サイズで開始し、getcwdバッファーが小さすぎるというエラーが表示された場合は、サイズを 2 倍にして再試行し、十分な大きさのバッファーが作成されて成功するまで繰り返します。

realloc最初の引数を NULL として呼び出すことは、 と同じであることに注意してくださいmalloc

于 2010-05-19T21:45:03.450 に答える
3

のコンストラクターに null ポインターを渡してはならないstd::stringため、返されるバッファー ポインターgetcwd()が null でないことを確認する必要があります。また、渡すバッファ ポインタはgetcwd() null であってはなりません

std::string getcwd() {
    char buf[FILENAME_MAX];
    char* succ = getcwd(buf, FILENAME_MAX);
    if( succ ) return std::string(succ);
    return "";  // raise a flag, throw an exception, ...
}
于 2010-05-19T21:45:27.210 に答える
2

ISO C++準拠のバージョンを使用することになっていると_getcwd思います。を返す意味はありません。 (少なくとも MSDN によると) をconst string使用して割り当てを解除する必要があります。free

string getcwd()
{
    char* a_cwd = _getcwd(NULL, 0);
    string s_cwd(a_cwd);
    free(a_cwd);
    return s_cwd;
}

もちろん、_getcwd()NULL を返すかどうかも確認する必要があります。

于 2010-05-19T21:46:45.523 に答える
1

a_cwd が NULL であることを確認する必要があります。その後、Mac、Windows、Linux で動作します。ただし、POSIX 準拠ではありません。

編集: perror はプログラムを終了しないため、終了するか、例外をスローするか、何かを行う必要があります。

于 2010-05-19T21:44:15.683 に答える
1

これはどう?短く、例外セーフで、リークしません。

std::string getcwd() {
    std::string result(1024,'\0');
    while( getcwd(&result[0], result.size()) == 0) {
        if( errno != ERANGE ) {
          throw std::runtime_error(strerror(errno));
        }
        result.resize(result.size()*2);
    }   
    result.resize(result.find('\0'));
    return result;
}
于 2010-05-21T14:35:38.847 に答える