很抱歉继续抨击这个,但我正在努力学习:)。这有什么好处吗?是的,我关心内存泄漏。我找不到预先分配char *的好方法,因为它似乎没有跨平台的方式。
const string getcwd()
{
char* a_cwd = getcwd(NULL,0);
string s_cwd(a_cwd);
free(a_cwd);
return s_cwd;
}
UPDATE2:没有Boost或Qt,最常见的东西可以啰嗦(见接受的答案)
答案 0 :(得分:7)
如果你想保持标准,如果你传递一个NULL,getcwd
不需要做任何事情;你应该在堆栈上为大多数场合(比如255个字符)分配一个“足够大”的缓冲区,但要准备好getcwd
可能失败的errno==ERANGE
;在这种情况下,你应该在dinamically分配一个更大的缓冲区,并在必要时增加它的大小。
这样的东西可以起作用(注意:没有经过测试,只是从头开始编写,可以肯定会有所改进):
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
:你绝对不应该这样做,请记住每个分配方法都有它的释放对应物,并且它们不能不匹配。
答案 1 :(得分:3)
这适用于Windows和Linux,因为当buf
的{{1}}参数为NULL时,它们都支持自动分配行为。但是,请注意,此行为不是标准,因此您可能会在更深奥的平台上遇到问题。
你可以这样做而不依赖于这种行为,但是:
getcwd
上面的代码以1024的缓冲区大小开始,然后,如果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
的第一个参数调用为NULL与realloc
相同。
答案 2 :(得分:2)
您不能将空指针传递给std::string
的构造函数,因此必须检查缓冲区指针getcwd()
返回值不为空。此外,您传递给getcwd()
must not be 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, ...
}
答案 3 :(得分:2)
我认为你应该使用符合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。
答案 4 :(得分:1)
您需要检查a_cwd是否为NULL。然后它将适用于Mac,Windows,Linux。但是,它不符合POSIX。
编辑:perror不会退出程序,所以你应该退出,抛出异常或做某事。
答案 5 :(得分: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;
}
答案 6 :(得分: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());
}