抱歉一直在强调这个问题,但我正在努力学习:)。这样行吗?是的,我关心内存泄漏。我找不到一个合适的预分配char*的方法,因为似乎没有跨平台的方法。
const string getcwd()
{
char* a_cwd = getcwd(NULL,0);
string s_cwd(a_cwd);
free(a_cwd);
return s_cwd;
}
更新2:没有使用Boost或Qt,最常见的东西可能会变得冗长(请参见被接受的答案)。
抱歉一直在强调这个问题,但我正在努力学习:)。这样行吗?是的,我关心内存泄漏。我找不到一个合适的预分配char*的方法,因为似乎没有跨平台的方法。
const string getcwd()
{
char* a_cwd = getcwd(NULL,0);
string s_cwd(a_cwd);
free(a_cwd);
return s_cwd;
}
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
释放a_cwd(在非标准扩展中,它可能是使用malloc或其他内存分配函数分配的,因为getcwd是为C而设计的),你绝对不应该这样做,记住每种分配方法都有其相应的释放方法,它们不能不匹配。
当传递给getcwd
函数的buf
参数为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;
}
getcwd
抱怨缓冲区太小,它会将缓冲区大小加倍并重试,直到有足够大的缓冲区并成功为止。realloc
的第一个参数调用NULL与malloc
相同。buf = realloc(buf, ...);
是不好的,因为如果 realloc()
失败,你会得到一个内存泄漏。所以为了真正严谨,你应该像这样做:tmp = realloc(buf, ...); if (tmp) buf = tmp; else { /* 处理错误 */ }
- Alok Singhal在构造函数中,您不能传递空指针给std::string
,因此必须检查getcwd()
返回的缓冲区指针不为空。另外,您传递给getcwd()
的缓冲区指针不能为空。
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, ...
}
我认为你应该使用符合ISO C++标准的版本_getcwd
。返回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。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;
}
result.resize(result.find('\0')-1);
這行程式碼中犯了一個 -1 的錯誤,因此你的結果是錯誤的... - Alexis Wilke你需要检查a_cwd是否为NULL。然后它将在Mac、Windows和Linux上工作。但是,它不符合POSIX标准。
编辑:perror不会退出程序,所以你应该退出、抛出异常或者做一些其他的操作。
当“字符串构造函数”为您完成一切时:
#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());
}
CAKE_getcwd
是什么?谷歌找不到相关信息。在Solaris上,普通的getcwd
不能按照你的期望工作。虽然当你传递一个空指针时它会分配内存,但它分配的内存量完全基于第二个getcwd
参数,而不是它想要返回的字符串长度。因此,在你的例子中,它将分配零字节(或者只是失败并返回EINVAL)。 - Rob Kennedy