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

顺便说一句,在你的代码中有一个非常错误的事情:你试图用delete:你绝对不应该这样做,请记住,每种分配方法都有其释放对应物,并且它们不能不匹配。

于 2010-05-19T21:45:06.573 回答
3

buf这将适用于 Windows 和 Linux,因为当参数getcwd为 NULL时,它们都支持自动分配行为。但是,请注意,这种行为不是标准的,因此您可能会在更深奥的平台上遇到问题。

但是,您可以在不依赖此行为的情况下执行此操作:

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抱怨缓冲区太小,它会加倍大小并再次尝试,并重复直到它有足够大的缓冲区并成功。

请注意,realloc第一个参数为 NULL 的调用与malloc.

于 2010-05-19T21:45:03.450 回答
3

您不能将空指针传递给 a 的构造函数std::string,因此您必须检查getcwd()返回的缓冲区指针是否为空。此外,您传递给的缓冲区指针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。返回 a 是没有意义的const string,您应该使用它free来解除分配(至少根据 MSDN):

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 回答
0

当“字符串构造函数”为您做所有事情时:

#include <stdio.h>  // defines FILENAME_MAX
#include <unistd.h> // for getcwd()

std::string GetCurrentWorkingDir()
{
    std::string cwd("\0",FILENAME_MAX+1);
    return getcwd(&cwd[0],cwd.capacity());
}
于 2019-04-26T13:11:27.990 回答