Sorry to keep hammering on this, but I\'m trying to learn :). Is this any good? And yes, I care about memory leaks. I can\'t find a decent way of preallocating the char*, be
If you want to remain standard, getcwd
isn't required to do anything if you pass to it a NULL; you should instead allocate on the stack a buffer that is "large enough" for most occasions (say, 255 characters), but be prepared for the occasion in which getcwd
may fail with errno==ERANGE
; in that case you should allocate dinamically a bigger buffer, and increase its size if necessary.
Something like this could work (notice: not tested, just written by scratch, can be surely improved):
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");
}
By the way, in your code there's a very wrong thing: you are trying to dellocate a_cwd (which presumably, in the nonstandard extension, is allocated with malloc or with some other memory allocation function, since getcwd is thought for C) with delete
: you absolutely shouldn't do that, keep in mind that each allocation method has its deallocation counterpart, and they must not be mismatched.
You must not pass a null pointer to the constructor of a std::string
, so you must check the buffer pointer getcwd()
returns isn't null. Also, the buffer pointer you pass to 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, ...
}
When "string constructor" do everything for you:
#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());
}
You need to check for a_cwd being NULL. Then it will work on Mac, Windows, Linux. However, it's not POSIX-compliant.
EDIT: perror doesn't exit the program, so you should exit, throw an exception, or do something.
How about this? It's short, exception safe, and doesn't leak.
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;
}
You're supposed to use the ISO C++ conformant version _getcwd
I think. There's no point returning a const string
, and you should use free
to deallocate (at least according to MSDN):
string getcwd()
{
char* a_cwd = _getcwd(NULL, 0);
string s_cwd(a_cwd);
free(a_cwd);
return s_cwd;
}
Of course you should also check if _getcwd()
returns NULL.